Skip to content

Commit 8b5029b

Browse files
make switch input (#1083)
1 parent 42c5d70 commit 8b5029b

File tree

8 files changed

+241
-1
lines changed

8 files changed

+241
-1
lines changed

pgml-dashboard/src/components/inputs/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ pub use range_group::RangeGroup;
99
pub mod select;
1010
pub use select::Select;
1111

12+
// src/components/inputs/switch
13+
pub mod switch;
14+
pub use switch::Switch;
15+
1216
// src/components/inputs/text
1317
pub mod text;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use crate::components::stimulus::stimulus_action::StimulusAction;
2+
use crate::components::stimulus::stimulus_target::StimulusTarget;
3+
use pgml_components::component;
4+
use sailfish::TemplateOnce;
5+
use std::fmt::{self, Display, Formatter};
6+
7+
pub enum State {
8+
Left,
9+
Right,
10+
}
11+
12+
impl Display for State {
13+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
14+
match self {
15+
State::Left => write!(f, "left"),
16+
State::Right => write!(f, "right"),
17+
}
18+
}
19+
}
20+
21+
#[derive(TemplateOnce)]
22+
#[template(path = "inputs/switch/template.html")]
23+
pub struct Switch {
24+
left_value: String,
25+
left_icon: String,
26+
right_value: String,
27+
right_icon: String,
28+
initial_state: State,
29+
on_toggle: Vec<StimulusAction>,
30+
target: StimulusTarget,
31+
}
32+
33+
impl Switch {
34+
pub fn new() -> Switch {
35+
Switch {
36+
left_value: String::from("left"),
37+
left_icon: String::from(""),
38+
right_value: String::from("right"),
39+
right_icon: String::from(""),
40+
on_toggle: Vec::new(),
41+
initial_state: State::Left,
42+
target: StimulusTarget::new(),
43+
}
44+
}
45+
46+
pub fn left(mut self, value: &str, icon: &str) -> Switch {
47+
self.left_value = value.into();
48+
self.left_icon = icon.into();
49+
self
50+
}
51+
52+
pub fn right(mut self, value: &str, icon: &str) -> Switch {
53+
self.right_value = value.into();
54+
self.right_icon = icon.into();
55+
self
56+
}
57+
58+
pub fn on_toggle(mut self, action: StimulusAction) -> Switch {
59+
self.on_toggle.push(action);
60+
self
61+
}
62+
63+
pub fn start_toggled(mut self) -> Switch {
64+
self.initial_state = State::Right;
65+
self
66+
}
67+
68+
pub fn target(mut self, target: StimulusTarget) -> Switch {
69+
self.target = target;
70+
self
71+
}
72+
}
73+
74+
component!(Switch);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
div[data-controller="inputs-switch"] {
2+
&.switch-container {
3+
background: #{$gray-100};
4+
border-radius: 5rem;
5+
border: 3px solid #{$gray-100};
6+
position: relative;
7+
}
8+
9+
.label {
10+
padding: 8px 20px;
11+
border-radius: 5rem;
12+
text-align: center;
13+
display: flex;
14+
@extend .gap-2;
15+
}
16+
17+
.toggle {
18+
background: #{$neon-shade-100};
19+
position: absolute;
20+
top: 0px;
21+
left: 0px;
22+
}
23+
24+
.choice {
25+
background: #{$gray-100};
26+
color: #{$neon-shade-100};
27+
flex: 1;
28+
29+
* {
30+
color: inherit;
31+
}
32+
}
33+
34+
.left {
35+
left: 0;
36+
transition: all $animation-timer;
37+
}
38+
39+
.right {
40+
left: 50%;
41+
transition: all $animation-timer;
42+
}
43+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Controller } from '@hotwired/stimulus'
2+
3+
export default class extends Controller {
4+
static targets = [
5+
"toggle",
6+
"toggleText",
7+
"toggleIcon",
8+
]
9+
10+
static values = {
11+
"left": String,
12+
"right": String,
13+
"initial": String,
14+
"leftIcon": String,
15+
"rightIcon": String,
16+
}
17+
18+
toggle() {
19+
if (this.toggleTarget.classList.contains('right')) {
20+
this.onToggleLeft()
21+
} else {
22+
this.onToggleRight()
23+
}
24+
}
25+
26+
onToggleLeft() {
27+
this.toggleTarget.classList.remove('right')
28+
this.toggleTarget.classList.add('left')
29+
this.toggleTextTarget.innerHTML = this.leftValue
30+
this.toggleIconTarget.innerHTML = this.leftIconValue
31+
this.element.dispatchEvent(new CustomEvent('toggle', {detail: this.leftValue}))
32+
}
33+
34+
onToggleRight() {
35+
this.toggleTarget.classList.remove('left')
36+
this.toggleTarget.classList.add('right')
37+
this.toggleTextTarget.innerHTML = this.rightValue
38+
this.toggleIconTarget.innerHTML = this.rightIconValue
39+
this.element.dispatchEvent(new CustomEvent('toggle', {detail: this.rightValue}))
40+
}
41+
42+
reset() {
43+
if( this.initialValue == "left" ) {
44+
console.log("toggling left")
45+
this.onToggleLeft()
46+
} else {
47+
console.log("toggling right")
48+
this.onToggleRight()
49+
}
50+
}
51+
52+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<% use crate::components::inputs::switch::State; %>
2+
<div data-controller="inputs-switch"
3+
class="switch-container d-flex flex-row"
4+
data-action='click->inputs-switch#toggle <% for action in on_toggle { %> toggle-><%- action %> <% } %> reset->inputs-switch#reset'
5+
data-inputs-switch-left-value="<%- left_value %>"
6+
data-inputs-switch-left-icon-value="<%- left_icon %>"
7+
data-inputs-switch-right-value="<%- right_value %>"
8+
data-inputs-switch-right-icon-value="<%- right_icon %>"
9+
data-inputs-switch-initial-value="<%- initial_state.to_string() %>"
10+
<%- target %>>
11+
<div class='label toggle w-50 <%- match initial_state {State::Left => "left".to_string(), State::Right => "right".to_string()} %>' data-inputs-switch-target="toggle">
12+
<span class="material-symbols-outlined" data-inputs-switch-target="toggleIcon" >
13+
<%- match initial_state {
14+
State::Left => left_icon.to_string(),
15+
State::Right => right_icon.to_string(),
16+
} %>
17+
</span>
18+
<h5 class="h5 my-0" data-inputs-switch-target="toggleText">
19+
<%- match initial_state {
20+
State::Left => left_value.to_string(),
21+
State::Right => right_value.to_string(),
22+
} %>
23+
</h5>
24+
</div>
25+
<div class="label choice">
26+
<span class="material-symbols-outlined" ><%- left_icon %></span>
27+
<h5 class="h5 my-0">
28+
<%- left_value %>
29+
</h5>
30+
</div>
31+
<div class="label choice">
32+
<span class="material-symbols-outlined"><%- right_icon %></span>
33+
<h5 class="h5 my-0">
34+
<%- right_value %>
35+
</h5>
36+
</div>
37+
</div>

pgml-dashboard/static/css/modules.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
@import "../../src/components/dropdown/dropdown.scss";
77
@import "../../src/components/inputs/range_group/range_group.scss";
88
@import "../../src/components/inputs/select/select.scss";
9+
@import "../../src/components/inputs/switch/switch.scss";
910
@import "../../src/components/inputs/text/editable_header/editable_header.scss";
1011
@import "../../src/components/left_nav_menu/left_nav_menu.scss";
1112
@import "../../src/components/modal/modal.scss";

pgml-dashboard/static/js/playground.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Controller } from '@hotwired/stimulus'
22

33
export default class extends Controller {
4-
static targets = ["test"]
4+
static targets = ["test", "switch"]
55

66
initialize() {
77
this.errorH3 = new CustomEvent("error", { detail: "message passed through event h3" })
@@ -31,4 +31,12 @@ export default class extends Controller {
3131
document.getElementById("header-2").dispatchEvent(this.clearH2)
3232
}
3333

34+
testOnToggleSwitch(e) {
35+
console.log("run from switch on toggle: ", e.detail)
36+
}
37+
38+
resetSwitch() {
39+
this.switchTarget.dispatchEvent(new Event("reset"))
40+
}
41+
3442
}

pgml-dashboard/templates/content/playground.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
use crate::components::inputs::range_group::RangeGroup;
55
use crate::components::inputs::text::editable_header::{EditableHeader, Headers};
66
use crate::components::stimulus::stimulus_target::StimulusTarget;
7+
use crate::components::stimulus::stimulus_action::StimulusAction;
8+
use crate::components::stimulus::stimulus_action::StimulusEvents;
79
use crate::components::inputs::select::Select;
10+
use crate::components::inputs::switch::Switch;
811
%>
912

1013
<div class="min-height: 100vh;" data-controller="playground">
@@ -155,6 +158,24 @@ <h3 class="h3">Inputs</h3>
155158
<button data-action="playground#clearError">Clear Error</button>
156159
</div>
157160
</div>
161+
<div class="d-flex flex-row justify-content-between">
162+
<div style="width: 30%">
163+
<%+ Switch::new()
164+
.on_toggle(
165+
StimulusAction::new()
166+
.controller("playground")
167+
.method("testOnToggleSwitch"))
168+
.target(StimulusTarget::new()
169+
.controller("playground")
170+
.name("switch"))
171+
.left("CPU", "memory")
172+
.right("GPU", "mode_fan")
173+
.start_toggled() %>
174+
</div>
175+
<div>
176+
<button data-action="click->playground#resetSwitch">Reset Switch</button>
177+
</div>
178+
</div>
158179
</div>
159180

160181
</div>

0 commit comments

Comments
 (0)