Skip to main content

ui_storybook/stories/
controls.rs

1//! Control-primitive stories (M-UI.4 / AUT-124).
2
3use leptos::prelude::*;
4
5use crate::components::primitives::{
6    ColorSwatch, IconButton, IconButtonVariant, Meter, Segment, SegmentedControl, SelectPill,
7    Slider, ToggleSwitch,
8};
9
10use super::{Story, StoryViewport, render};
11
12/// All control-primitive stories.
13#[must_use]
14pub fn stories() -> Vec<Story> {
15    vec![
16        Story {
17            id: "controls-buttons-icon-buttons",
18            category: "Primitives",
19            title: "Controls — icon buttons",
20            viewport: StoryViewport::Auto,
21            render: render_icon_buttons,
22        },
23        Story {
24            id: "controls-toggle-states",
25            category: "Primitives",
26            title: "Controls — toggle switch states",
27            viewport: StoryViewport::Auto,
28            render: render_toggle_states,
29        },
30        Story {
31            id: "controls-segmented-record-mode",
32            category: "Primitives",
33            title: "Controls — segmented record mode",
34            viewport: StoryViewport::Auto,
35            render: render_segmented,
36        },
37        Story {
38            id: "controls-slider-values",
39            category: "Primitives",
40            title: "Controls — slider matrix",
41            viewport: StoryViewport::Auto,
42            render: render_sliders,
43        },
44        Story {
45            id: "controls-color-swatches",
46            category: "Primitives",
47            title: "Controls — color swatches",
48            viewport: StoryViewport::Auto,
49            render: render_color_swatches,
50        },
51        Story {
52            id: "controls-meters",
53            category: "Primitives",
54            title: "Controls — audio level meters",
55            viewport: StoryViewport::Auto,
56            render: render_meters,
57        },
58    ]
59}
60
61fn render_icon_buttons() -> String {
62    render(view! {
63        <div class="story-row" style="padding:14px;gap:14px">
64            <IconButton glyph="●" label="Record" variant=IconButtonVariant::Danger />
65            <IconButton glyph="◼" label="Stop" variant=IconButtonVariant::Filled />
66            <IconButton glyph="↻" label="Reset" variant=IconButtonVariant::Ghost />
67            <IconButton glyph="✱" label="Pinned" variant=IconButtonVariant::Ghost pressed=true />
68            <IconButton glyph="⌫" label="Delete" variant=IconButtonVariant::Ghost disabled=true />
69        </div>
70    })
71}
72
73fn render_toggle_states() -> String {
74    render(view! {
75        <div class="story-row" style="padding:14px;gap:20px">
76            <div class="story-row" style="flex-direction:column;align-items:center;gap:6px">
77                <ToggleSwitch checked=false label="off" />
78                <span style="font-size:11px;color:var(--text-tertiary)">"Off"</span>
79            </div>
80            <div class="story-row" style="flex-direction:column;align-items:center;gap:6px">
81                <ToggleSwitch checked=true label="on" />
82                <span style="font-size:11px;color:var(--text-tertiary)">"On"</span>
83            </div>
84            <div class="story-row" style="flex-direction:column;align-items:center;gap:6px">
85                <ToggleSwitch checked=false disabled=true label="disabled off" />
86                <span style="font-size:11px;color:var(--text-tertiary)">"Disabled off"</span>
87            </div>
88            <div class="story-row" style="flex-direction:column;align-items:center;gap:6px">
89                <ToggleSwitch checked=true disabled=true label="disabled on" />
90                <span style="font-size:11px;color:var(--text-tertiary)">"Disabled on"</span>
91            </div>
92        </div>
93    })
94}
95
96fn render_segmented() -> String {
97    let segments = vec![
98        Segment {
99            id: "screen",
100            label: "Screen",
101            icon: Some("▢"),
102            disabled: false,
103        },
104        Segment {
105            id: "window",
106            label: "Window",
107            icon: Some("◫"),
108            disabled: false,
109        },
110        Segment {
111            id: "area",
112            label: "Area",
113            icon: Some("⊞"),
114            disabled: false,
115        },
116    ];
117    render(view! {
118        <div style="padding:14px;display:flex;flex-direction:column;gap:14px;align-items:flex-start">
119            <SegmentedControl segments=segments.clone() active="screen" label="Capture mode" />
120            <SegmentedControl segments=segments.clone() active="window" label="Capture mode (window)" />
121            <SegmentedControl segments=segments active="area" label="Capture mode (area)" />
122        </div>
123    })
124}
125
126fn render_sliders() -> String {
127    render(view! {
128        <div style="padding:14px;display:flex;flex-direction:column;gap:14px;width:360px">
129            <Slider value=0.0 label="Min".to_string() readout="0%".to_string() />
130            <Slider value=0.42 label="Volume".to_string() readout="42%".to_string() />
131            <Slider value=1.0 label="Max".to_string() readout="100%".to_string() />
132            <Slider value=0.5 min=0.0 max=10.0 label="Disabled".to_string() readout="5.0".to_string() disabled=true />
133        </div>
134    })
135}
136
137fn render_color_swatches() -> String {
138    render(view! {
139        <div class="story-row" style="padding:14px;gap:10px">
140            <ColorSwatch color="#fafafa".to_string() label="White".to_string() selected=true />
141            <ColorSwatch color="#ef4444".to_string() label="Red".to_string() />
142            <ColorSwatch color="#f59e0b".to_string() label="Amber".to_string() />
143            <ColorSwatch color="#10b981".to_string() label="Emerald".to_string() />
144            <ColorSwatch color="#38bdf8".to_string() label="Sky".to_string() />
145            <ColorSwatch color="#a78bfa".to_string() label="Violet".to_string() />
146            <ColorSwatch color="#18181b".to_string() label="Zinc".to_string() />
147        </div>
148    })
149}
150
151fn render_meters() -> String {
152    render(view! {
153        <div style="padding:14px;display:flex;flex-direction:column;gap:10px;width:280px">
154            <div class="story-row" style="gap:10px">
155                <span style="width:60px;font-size:11px;color:var(--text-secondary)">"Silent"</span>
156                <Meter level=0.0 />
157            </div>
158            <div class="story-row" style="gap:10px">
159                <span style="width:60px;font-size:11px;color:var(--text-secondary)">"Low"</span>
160                <Meter level=0.25 />
161            </div>
162            <div class="story-row" style="gap:10px">
163                <span style="width:60px;font-size:11px;color:var(--text-secondary)">"Mid"</span>
164                <Meter level=0.6 />
165            </div>
166            <div class="story-row" style="gap:10px">
167                <span style="width:60px;font-size:11px;color:var(--text-secondary)">"Loud"</span>
168                <Meter level=0.85 />
169            </div>
170            <div class="story-row" style="gap:10px">
171                <span style="width:60px;font-size:11px;color:var(--text-secondary)">"Clipping"</span>
172                <Meter level=1.0 danger=true />
173            </div>
174            <SelectPill icon="🎙".to_string() label="Built-in microphone".to_string() />
175        </div>
176    })
177}