1use gpui::{prelude::*, Context, Entity};
2use allui::prelude::*;
3
4use crate::Storybook;
5
6pub fn render_text_story() -> impl IntoElement {
7 VStack::new()
8 .spacing(16.0)
9 .alignment(HorizontalAlignment::Leading)
10 .child(Text::new("Text Styles").font(Font::headline()))
11 .child(
12 VStack::new()
13 .spacing(8.0)
14 .alignment(HorizontalAlignment::Leading)
15 .child(Text::new("Large Title").font(Font::large_title()))
16 .child(Text::new("Title").font(Font::title()))
17 .child(Text::new("Headline").font(Font::headline()))
18 .child(Text::new("Body text").font(Font::body()))
19 .child(
20 Text::new("Caption")
21 .font(Font::caption())
22 .foreground_color(Color::gray()),
23 )
24 .padding(16.0)
25 .background(Color::tertiary_system_background())
26 .corner_radius(8.0),
27 )
28 .child(Text::new("Font Variations").font(Font::headline()))
29 .child(
30 VStack::new()
31 .spacing(8.0)
32 .alignment(HorizontalAlignment::Leading)
33 .child(Text::new("Bold text").bold())
34 .child(Text::new("Italic text").italic())
35 .child(Text::new("Bold + Italic").bold().italic())
36 .child(Text::new("Colored text").foreground_color(Color::blue()))
37 .padding(16.0)
38 .background(Color::tertiary_system_background())
39 .corner_radius(8.0),
40 )
41 .child(Text::new("Font Design").font(Font::headline()))
42 .child(
43 VStack::new()
44 .spacing(8.0)
45 .alignment(HorizontalAlignment::Leading)
46 .child(Text::new("Default: The quick brown fox"))
47 .child(
48 Text::new("Monospaced: let x = 42;")
49 .font(Font::body().monospaced()),
50 )
51 .child(
52 Text::new("Serif: Classical typography")
53 .font(Font::body().design(FontDesign::Serif)),
54 )
55 .child(
56 Text::new("Rounded: Friendly appearance")
57 .font(Font::body().design(FontDesign::Rounded)),
58 )
59 .padding(16.0)
60 .background(Color::tertiary_system_background())
61 .corner_radius(8.0),
62 )
63 .child(Text::new("Text Decorations").font(Font::headline()))
64 .child(
65 VStack::new()
66 .spacing(8.0)
67 .alignment(HorizontalAlignment::Leading)
68 .child(Text::new("Normal text"))
69 .child(Text::new("Strikethrough text").strikethrough(true))
70 .child(
71 Text::new("Strikethrough + Red")
72 .strikethrough(true)
73 .foreground_color(Color::red()),
74 )
75 .padding(16.0)
76 .background(Color::tertiary_system_background())
77 .corner_radius(8.0),
78 )
79 .child(Text::new("Line Limit").font(Font::headline()))
80 .child(
81 VStack::new()
82 .spacing(12.0)
83 .alignment(HorizontalAlignment::Leading)
84 .child(
85 VStack::new()
86 .spacing(4.0)
87 .alignment(HorizontalAlignment::Leading)
88 .child(Text::new(".line_limit(1):").foreground_color(Color::gray()))
89 .child(
90 Text::new("This is a very long text that should be truncated to a single line when line_limit is set to 1.")
91 .line_limit(1)
92 .frame_width(300.0)
93 ),
94 )
95 .child(
96 VStack::new()
97 .spacing(4.0)
98 .alignment(HorizontalAlignment::Leading)
99 .child(Text::new(".line_limit(2):").foreground_color(Color::gray()))
100 .child(
101 Text::new("This is a very long text that demonstrates the line_limit modifier. It should wrap to two lines maximum and then truncate any remaining content.")
102 .line_limit(2)
103 .frame_width(300.0)
104 ),
105 )
106 .padding(16.0)
107 .background(Color::tertiary_system_background())
108 .corner_radius(8.0),
109 )
110}
111
112pub fn render_button_story() -> impl IntoElement {
113 VStack::new()
114 .spacing(12.0)
115 .alignment(HorizontalAlignment::Leading)
116 .child(
117 Button::new("Bordered Prominent", || {
118 println!("Bordered Prominent clicked!");
119 })
120 .button_style(ButtonStyle::BorderedProminent),
121 )
122 .child(
123 Button::new("Bordered", || {
124 println!("Bordered clicked!");
125 })
126 .button_style(ButtonStyle::Bordered),
127 )
128 .child(
129 Button::new("Plain", || {
130 println!("Plain clicked!");
131 })
132 .button_style(ButtonStyle::Plain),
133 )
134 .child(
135 Button::new("Disabled", || {})
136 .button_style(ButtonStyle::BorderedProminent)
137 .disabled(true),
138 )
139}
140
141pub fn render_modifiers_story() -> impl IntoElement {
142 VStack::new()
143 .spacing(16.0)
144 .alignment(HorizontalAlignment::Leading)
145 .child(Text::new("Modifier order matters:"))
146 .child(
147 HStack::new()
148 .spacing(32.0)
149 .child(
150 VStack::new()
151 .spacing(8.0)
152 .child(Text::new(".padding().background()"))
153 .child(Text::new("Hello").padding(16.0).background(Color::red())),
154 )
155 .child(
156 VStack::new()
157 .spacing(8.0)
158 .child(Text::new(".background().padding()"))
159 .child(Text::new("Hello").background(Color::red()).padding(16.0)),
160 ),
161 )
162 .child(Text::new("Chained modifiers:"))
163 .child(
164 Text::new("Styled Text")
165 .padding(12.0)
166 .background(Color::blue())
167 .corner_radius(8.0)
168 .padding(4.0)
169 .background(Color::green())
170 .corner_radius(12.0),
171 )
172}
173
174pub fn render_toggle_story(storybook: &Storybook, cx: &mut Context<Storybook>) -> impl IntoElement {
175 let toggle_value = storybook.toggle_value;
176
177 VStack::new()
178 .spacing(16.0)
179 .alignment(HorizontalAlignment::Leading)
180 .child(Text::new("Toggle - Boolean switch component:"))
181 .child(
182 VStack::new()
183 .spacing(12.0)
184 .child(
185 HStack::new()
186 .spacing(12.0)
187 .child(Toggle::new_with_handler(
188 "Dark Mode",
189 toggle_value,
190 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
191 this.toggle_value = *checked;
192 cx.notify();
193 }),
194 ))
195 .child(
196 Text::new(if toggle_value { "ON" } else { "OFF" }).foreground_color(
197 if toggle_value {
198 Color::green()
199 } else {
200 Color::gray()
201 },
202 ),
203 ),
204 )
205 .child(Toggle::new("Disabled Toggle", true, |_| {}).disabled(true))
206 .padding(16.0)
207 .background(Color::tertiary_system_background())
208 .corner_radius(8.0),
209 )
210 .child(
211 Text::new("Note: Toggle wraps gpui-component's Switch.")
212 .foreground_color(Color::gray()),
213 )
214}
215
216pub fn render_tap_gesture_story(
217 storybook: &Storybook,
218 cx: &mut Context<Storybook>,
219) -> impl IntoElement {
220 let tap_count = storybook.tap_count;
221 let entity = cx.entity().clone();
222
223 VStack::new()
224 .spacing(16.0)
225 .alignment(HorizontalAlignment::Leading)
226 .child(Text::new("on_tap_gesture - Add tap handlers to any view:"))
227 .child(
228 VStack::new()
229 .spacing(12.0)
230 .child(
231 Text::new("Tap me!")
232 .padding(16.0)
233 .background(Color::blue())
234 .corner_radius(8.0)
235 .on_tap_gesture_with("tap-me-button", move |_event, _window, cx| {
236 entity.update(cx, |this, cx| {
237 this.tap_count += 1;
238 cx.notify();
239 });
240 }),
241 )
242 .child(
243 Text::new(format!("Tap count: {}", tap_count)).foreground_color(Color::green()),
244 )
245 .padding(16.0)
246 .background(Color::tertiary_system_background())
247 .corner_radius(8.0),
248 )
249 .child(
250 Text::new("Any view can be made tappable with .on_tap_gesture()")
251 .foreground_color(Color::gray()),
252 )
253}
254
255pub fn render_textfields_story(
256 text_input: &Entity<InputState>,
257 text_input_cleanable: &Entity<InputState>,
258 password_input: &Entity<InputState>,
259) -> impl IntoElement {
260 VStack::new()
261 .spacing(16.0)
262 .alignment(HorizontalAlignment::Leading)
263 .child(Text::new("TextField - Single-line text input:"))
264 .child(
265 VStack::new()
266 .spacing(12.0)
267 .alignment(HorizontalAlignment::Leading)
268 .child(Text::new("Basic TextField:").foreground_color(Color::gray()))
269 .child(TextField::new(text_input).frame_width(300.0))
270 .child(
271 Text::new("TextField with cleanable (x button):")
272 .foreground_color(Color::gray()),
273 )
274 .child(
275 TextField::new(text_input_cleanable)
276 .cleanable(true)
277 .frame_width(300.0),
278 )
279 .padding(16.0)
280 .background(Color::tertiary_system_background())
281 .corner_radius(8.0),
282 )
283 .child(Text::new("SecureField - Password input (masked):"))
284 .child(
285 VStack::new()
286 .spacing(12.0)
287 .alignment(HorizontalAlignment::Leading)
288 .child(
289 SecureField::new(password_input)
290 .show_toggle(true)
291 .frame_width(300.0),
292 )
293 .padding(16.0)
294 .background(Color::tertiary_system_background())
295 .corner_radius(8.0),
296 )
297 .child(
298 Text::new("Note: State is managed via Entity<InputState>")
299 .foreground_color(Color::gray()),
300 )
301}
302
303pub fn render_sliders_story(
304 slider_state: &Entity<SliderState>,
305 slider_value: f32,
306) -> impl IntoElement {
307 VStack::new()
308 .spacing(16.0)
309 .alignment(HorizontalAlignment::Leading)
310 .child(Text::new("Slider - Range value selection:"))
311 .child(
312 VStack::new()
313 .spacing(12.0)
314 .alignment(HorizontalAlignment::Leading)
315 .child(Text::new("Horizontal slider:").foreground_color(Color::gray()))
316 .child(
317 HStack::new()
318 .spacing(16.0)
319 .child(Slider::new(slider_state).frame_width(200.0))
320 .child(
321 Text::new(format!("{:.0}", slider_value))
322 .foreground_color(Color::green()),
323 ),
324 )
325 .child(
326 Text::new(format!("Current value: {:.1}", slider_value))
327 .foreground_color(Color::gray()),
328 )
329 .padding(16.0)
330 .background(Color::tertiary_system_background())
331 .corner_radius(8.0),
332 )
333 .child(
334 Text::new("Note: Subscribe to SliderEvent for value changes")
335 .foreground_color(Color::gray()),
336 )
337}
338
339pub fn render_more_inputs_story(
340 text_editor_input: &Entity<InputState>,
341 stepper_input: &Entity<InputState>,
342 stepper_value: i32,
343) -> impl IntoElement {
344 VStack::new()
345 .spacing(16.0)
346 .alignment(HorizontalAlignment::Leading)
347 .child(Text::new("TextEditor - Multi-line text input:"))
348 .child(
349 VStack::new()
350 .spacing(8.0)
351 .alignment(HorizontalAlignment::Leading)
352 .child(
353 TextEditor::new(text_editor_input)
354 .height(150.0)
355 .frame_width(300.0),
356 )
357 .child(
358 Text::new("Note: Create InputState with .multi_line(true)")
359 .foreground_color(Color::gray()),
360 )
361 .padding(16.0)
362 .background(Color::tertiary_system_background())
363 .corner_radius(8.0),
364 )
365 .child(Text::new("Stepper - Increment/decrement control:"))
366 .child(
367 VStack::new()
368 .spacing(12.0)
369 .alignment(HorizontalAlignment::Leading)
370 .child(
371 HStack::new()
372 .spacing(16.0)
373 .child(Text::new(format!("Value: {}", stepper_value)))
374 .child(Stepper::new(stepper_input)),
375 )
376 .child(
377 Text::new("Stepper triggers increment/decrement callbacks")
378 .foreground_color(Color::gray()),
379 )
380 .padding(16.0)
381 .background(Color::tertiary_system_background())
382 .corner_radius(8.0),
383 )
384 .child(Text::new("Picker - Selection from options:"))
385 .child(
386 VStack::new()
387 .spacing(8.0)
388 .alignment(HorizontalAlignment::Leading)
389 .child(
390 Text::new(
391 "Picker requires PickerState + PickerDelegate. See picker.rs for usage.",
392 )
393 .foreground_color(Color::gray()),
394 )
395 .child(
396 VStack::new()
397 .spacing(4.0)
398 .child(Text::new("Usage:").bold())
399 .child(
400 Text::new("let state = PickerState::new(...);")
401 .font(Font::caption())
402 .foreground_color(Color::tertiary_label()),
403 )
404 .child(
405 Text::new("Picker::new(\"id\", &state).build(window, cx)")
406 .font(Font::caption())
407 .foreground_color(Color::tertiary_label()),
408 )
409 .padding(12.0)
410 .background(Color::secondary_system_background())
411 .corner_radius(8.0),
412 )
413 .padding(16.0)
414 .background(Color::tertiary_system_background())
415 .corner_radius(8.0),
416 )
417}
418
419pub fn render_display_components_story() -> impl IntoElement {
420 VStack::new()
421 .spacing(16.0)
422 .alignment(HorizontalAlignment::Leading)
423 .child(Text::new("Divider").font(Font::headline()))
424 .child(
425 VStack::new()
426 .spacing(8.0)
427 .alignment(HorizontalAlignment::Leading)
428 .child(Text::new("Item above"))
429 .child(Divider::new())
430 .child(Text::new("Item below"))
431 .padding(16.0)
432 .background(Color::tertiary_system_background())
433 .corner_radius(8.0)
434 .frame_width(300.0),
435 )
436 .child(Text::new("Label").font(Font::headline()))
437 .child(
438 VStack::new()
439 .spacing(8.0)
440 .alignment(HorizontalAlignment::Leading)
441 .child(Label::new("star.fill", "Favorites"))
442 .child(Label::new("folder", "Documents"))
443 .child(Label::new("gear", "Settings"))
444 .padding(16.0)
445 .background(Color::tertiary_system_background())
446 .corner_radius(8.0),
447 )
448 .child(Text::new("Link").font(Font::headline()))
449 .child(
450 VStack::new()
451 .spacing(8.0)
452 .alignment(HorizontalAlignment::Leading)
453 .child(Link::new("Visit Allui", || {
454 println!("Link clicked: Visit Allui");
455 }))
456 .child(Link::new("Documentation", || {
457 println!("Link clicked: Documentation");
458 }))
459 .padding(16.0)
460 .background(Color::tertiary_system_background())
461 .corner_radius(8.0),
462 )
463 .child(Text::new("ProgressView").font(Font::headline()))
464 .child(
465 VStack::new()
466 .spacing(12.0)
467 .alignment(HorizontalAlignment::Leading)
468 .child(Text::new("Linear (determinate):").foreground_color(Color::gray()))
469 .child(
470 ProgressView::new()
471 .progress_view_style(ProgressViewStyle::Linear)
472 .value(0.65)
473 .frame_width(200.0),
474 )
475 .child(Text::new("Circular (indeterminate):").foreground_color(Color::gray()))
476 .child(ProgressView::new().progress_view_style(ProgressViewStyle::Circular))
477 .padding(16.0)
478 .background(Color::tertiary_system_background())
479 .corner_radius(8.0),
480 )
481 .child(Text::new("Image").font(Font::headline()))
482 .child(
483 VStack::new()
484 .spacing(8.0)
485 .alignment(HorizontalAlignment::Leading)
486 .child(
487 Text::new("Note: Image currently renders placeholder text.")
488 .foreground_color(Color::gray()),
489 )
490 .child(Image::new("photo.jpg").frame_size(100.0, 100.0))
491 .padding(16.0)
492 .background(Color::tertiary_system_background())
493 .corner_radius(8.0),
494 )
495}