ui_storybook/stories/
primitives.rs1use leptos::prelude::*;
6
7use crate::components::primitives::{
8 Badge, BadgeKind, Button, ButtonSize, ButtonVariant, Card, CardBody, CardHeader, Divider,
9 DividerOrientation, IconTile, IconTileKind, Kbd, Surface, SurfaceKind,
10};
11
12use super::{Story, StoryViewport, render};
13
14#[must_use]
16pub fn stories() -> Vec<Story> {
17 vec![
18 Story {
19 id: "button-variants",
20 category: "Primitives",
21 title: "Button — variants",
22 viewport: StoryViewport::Auto,
23 render: render_button_variants,
24 },
25 Story {
26 id: "button-sizes",
27 category: "Primitives",
28 title: "Button — sizes",
29 viewport: StoryViewport::Auto,
30 render: render_button_sizes,
31 },
32 Story {
33 id: "card-basic",
34 category: "Primitives",
35 title: "Card — header + body",
36 viewport: StoryViewport::Auto,
37 render: render_card_basic,
38 },
39 Story {
40 id: "tokens-dark-zinc",
41 category: "Primitives",
42 title: "Tokens — semantic surface + text",
43 viewport: StoryViewport::Auto,
44 render: render_tokens_dark_zinc,
45 },
46 Story {
47 id: "surface-stack",
48 category: "Primitives",
49 title: "Surface — five kinds stacked",
50 viewport: StoryViewport::Auto,
51 render: render_surface_stack,
52 },
53 Story {
54 id: "badge-variants",
55 category: "Primitives",
56 title: "Badge — six kinds",
57 viewport: StoryViewport::Auto,
58 render: render_badge_variants,
59 },
60 Story {
61 id: "kbd-shortcuts",
62 category: "Primitives",
63 title: "Kbd — keyboard shortcut chips",
64 viewport: StoryViewport::Auto,
65 render: render_kbd_shortcuts,
66 },
67 Story {
68 id: "icon-tile-variants",
69 category: "Primitives",
70 title: "IconTile — five kinds",
71 viewport: StoryViewport::Auto,
72 render: render_icon_tile_variants,
73 },
74 ]
75}
76
77fn render_button_variants() -> String {
78 render(view! {
79 <div class="story-row">
80 <Button variant=ButtonVariant::Default>"Default"</Button>
81 <Button variant=ButtonVariant::Outline>"Outline"</Button>
82 <Button variant=ButtonVariant::Ghost>"Ghost"</Button>
83 <Button variant=ButtonVariant::Destructive>"Destructive"</Button>
84 <Button variant=ButtonVariant::Secondary>"Secondary"</Button>
85 </div>
86 })
87}
88
89fn render_button_sizes() -> String {
90 render(view! {
91 <div class="story-row">
92 <Button size=ButtonSize::Sm>"Small"</Button>
93 <Button size=ButtonSize::Md>"Medium"</Button>
94 <Button size=ButtonSize::Lg>"Large"</Button>
95 <Button disabled=true>"Disabled"</Button>
96 </div>
97 })
98}
99
100fn render_card_basic() -> String {
101 render(view! {
102 <Card>
103 <CardHeader title="Recording 01" subtitle="Captured 2026-05-08 · 1m 24s" />
104 <CardBody>
105 <p>"Drag the file onto the player or hit "<kbd>"⌘O"</kbd>" to import."</p>
106 <div class="story-row">
107 <Button variant=ButtonVariant::Default>"Open editor"</Button>
108 <Button variant=ButtonVariant::Ghost>"Reveal in Finder"</Button>
109 </div>
110 </CardBody>
111 </Card>
112 })
113}
114
115fn render_tokens_dark_zinc() -> String {
116 render(view! {
120 <div class="token-grid">
121 <div class="token-name">"--surface-base"</div>
122 <div class="token-swatch" style="background:var(--surface-base)"></div>
123 <div class="token-value">"App background"</div>
124
125 <div class="token-name">"--surface-elevated"</div>
126 <div class="token-swatch" style="background:var(--surface-elevated)"></div>
127 <div class="token-value">"Panels + cards"</div>
128
129 <div class="token-name">"--surface-popover"</div>
130 <div class="token-swatch" style="background:var(--surface-popover)"></div>
131 <div class="token-value">"Menus + popovers"</div>
132
133 <div class="token-name">"--surface-selected"</div>
134 <div class="token-swatch" style="background:var(--surface-selected)"></div>
135 <div class="token-value">"Selected row inside a menu"</div>
136
137 <div class="token-name">"--text-primary"</div>
138 <div class="token-swatch" style="background:var(--text-primary)"></div>
139 <div class="token-value">"Default text colour"</div>
140
141 <div class="token-name">"--text-secondary"</div>
142 <div class="token-swatch" style="background:var(--text-secondary)"></div>
143 <div class="token-value">"Muted labels"</div>
144
145 <div class="token-name">"--text-tertiary"</div>
146 <div class="token-swatch" style="background:var(--text-tertiary)"></div>
147 <div class="token-value">"Footnotes + axis labels"</div>
148
149 <div class="token-name">"--action-record"</div>
150 <div class="token-swatch" style="background:var(--action-record)"></div>
151 <div class="token-value">"Record / destructive action"</div>
152 </div>
153 })
154}
155
156fn render_surface_stack() -> String {
157 render(view! {
158 <div class="surface-stack">
159 <Surface kind=SurfaceKind::Base>
160 <div class="surface-demo">"surface-base — the app canvas"</div>
161 </Surface>
162 <Surface kind=SurfaceKind::Elevated>
163 <div class="surface-demo">"surface-elevated — panels + cards"</div>
164 </Surface>
165 <Surface kind=SurfaceKind::Popover>
166 <div class="surface-demo">"surface-popover — menus + tray popovers"</div>
167 </Surface>
168 <Surface kind=SurfaceKind::Selected>
169 <div class="surface-demo">"surface-selected — highlighted row inside a menu"</div>
170 </Surface>
171 <Surface kind=SurfaceKind::Glass>
172 <div class="surface-demo">"surface-glass — overlay over recording"</div>
173 </Surface>
174 </div>
175 })
176}
177
178fn render_badge_variants() -> String {
179 render(view! {
180 <div class="badge-row">
181 <Badge kind=BadgeKind::Neutral>"Beta"</Badge>
182 <Badge kind=BadgeKind::Accent>"New"</Badge>
183 <Badge kind=BadgeKind::Danger>"Failed"</Badge>
184 <Badge kind=BadgeKind::Live>"Live"</Badge>
185 <Badge kind=BadgeKind::Plan>"Pro"</Badge>
186 <Badge kind=BadgeKind::Count>"12"</Badge>
187 <Divider orientation=DividerOrientation::Vertical />
188 <span style="font-size:11px;color:var(--text-tertiary)">"divider shown inline (vertical)"</span>
189 </div>
190 })
191}
192
193fn render_kbd_shortcuts() -> String {
194 render(view! {
195 <div class="story-row" style="padding:14px;flex-direction:column;align-items:flex-start;gap:10px">
196 <div class="story-row">
197 <span style="font-size:12px;color:var(--text-secondary)">"Start recording"</span>
198 <Kbd keys=vec!["⌘", "⇧", "R"] />
199 </div>
200 <div class="story-row">
201 <span style="font-size:12px;color:var(--text-secondary)">"Stop recording"</span>
202 <Kbd keys=vec!["⌘", "⇧", "S"] />
203 </div>
204 <div class="story-row">
205 <span style="font-size:12px;color:var(--text-secondary)">"Pause / resume"</span>
206 <Kbd keys=vec!["Space"] />
207 </div>
208 <div class="story-row">
209 <span style="font-size:12px;color:var(--text-secondary)">"Open editor"</span>
210 <Kbd keys=vec!["⌘", "O"] />
211 </div>
212 </div>
213 })
214}
215
216fn render_icon_tile_variants() -> String {
217 render(view! {
218 <div class="story-row" style="padding:14px;gap:14px">
219 <div class="story-row" style="flex-direction:column;gap:4px">
220 <IconTile kind=IconTileKind::Workspace>"PE"</IconTile>
221 <span style="font-size:11px;color:var(--text-tertiary)">"Workspace"</span>
222 </div>
223 <div class="story-row" style="flex-direction:column;gap:4px">
224 <IconTile kind=IconTileKind::Device>"🎙"</IconTile>
225 <span style="font-size:11px;color:var(--text-tertiary)">"Device"</span>
226 </div>
227 <div class="story-row" style="flex-direction:column;gap:4px">
228 <IconTile kind=IconTileKind::App>"S"</IconTile>
229 <span style="font-size:11px;color:var(--text-tertiary)">"App"</span>
230 </div>
231 <div class="story-row" style="flex-direction:column;gap:4px">
232 <IconTile kind=IconTileKind::Action>"+"</IconTile>
233 <span style="font-size:11px;color:var(--text-tertiary)">"Action"</span>
234 </div>
235 <div class="story-row" style="flex-direction:column;gap:4px">
236 <IconTile kind=IconTileKind::User>"M"</IconTile>
237 <span style="font-size:11px;color:var(--text-tertiary)">"User"</span>
238 </div>
239 </div>
240 })
241}