ui_storybook/stories/mod.rs
1//! Story registry — every UI component must have at least one story.
2//!
3//! Each story is a `(id, render)` pair. The render closure produces an
4//! `IntoView` so it can be SSR-rendered to HTML for snapshot tests AND mounted
5//! in the browser via Trunk for visual review.
6//!
7//! Stories are split across per-surface sub-modules
8//! ([`primitives`] / [`shell`] / [`recorder`] / [`editor`] /
9//! [`menus`] / [`library`] / [`cursor`]) but every shipped story is
10//! re-collected into [`all_stories`] in the order they should appear in
11//! the gallery sidebar. The flat registry is what
12//! `ui_storybook::tests::snapshots` and the `ui-export-stories` binary
13//! both consume — they don't need to know about the per-surface split.
14
15pub mod controls;
16pub mod cursor;
17pub mod editor;
18pub mod fixtures_gallery;
19pub mod library;
20pub mod menus;
21pub mod primitives;
22pub mod recorder;
23pub mod recorder_audio;
24pub mod recorder_devices;
25pub mod recorder_display;
26pub mod recorder_footer;
27pub mod recorder_on_screen;
28pub mod recording_status;
29pub mod save_panel;
30pub mod shell;
31pub mod tray_record_popover;
32pub mod workspace_menu;
33
34/// Viewport hint for a story. Drives how the storybook exporter sizes
35/// the surrounding chrome and how mdBook's `<iframe>` height is set.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
37pub enum StoryViewport {
38 /// Let the content size itself. The exporter picks a sensible default
39 /// height per category.
40 #[default]
41 Auto,
42 /// Fixed-pixel viewport — used by popovers, tray surfaces, and any
43 /// component whose layout depends on the surrounding window size.
44 Fixed {
45 /// Viewport width in CSS pixels.
46 width: u16,
47 /// Viewport height in CSS pixels.
48 height: u16,
49 },
50 /// Tall, narrow viewport — used by inspector panels, sidebars, and
51 /// other vertically-scrolling surfaces. Height is determined by the
52 /// content; width is fixed.
53 TallPanel {
54 /// Viewport width in CSS pixels.
55 width: u16,
56 },
57}
58
59/// One UI gallery story — a closure that renders an `IntoView` to its SSR
60/// HTML string, plus identifying metadata.
61pub struct Story {
62 /// Stable kebab-case identifier — also the asset filename
63 /// (`_docs/book/src/assets/ui/<id>.html`).
64 pub id: &'static str,
65 /// Logical bucket in the gallery (e.g. `"Primitives"`, `"Editor"`).
66 pub category: &'static str,
67 /// Display title shown in the gallery sidebar.
68 pub title: &'static str,
69 /// Viewport hint for the exporter / mdBook.
70 pub viewport: StoryViewport,
71 /// Render closure — produces SSR HTML synchronously.
72 pub render: fn() -> String,
73}
74
75/// Render any Leptos view to a plain HTML string. Used by every story
76/// renderer in the per-surface modules.
77///
78/// `RenderHtml::to_html` is brought into scope via `leptos::prelude::*`
79/// (which re-exports `tachys::prelude::*`). It takes the view by value
80/// and walks it into a synchronous HTML string — exactly what we want
81/// for an insta snapshot.
82pub(crate) fn render<V>(view: V) -> String
83where
84 V: leptos::IntoView,
85{
86 use leptos::prelude::*;
87 view.into_view().to_html()
88}
89
90/// Every shipped story, in display order. Aggregates the per-surface
91/// `stories()` lists so the snapshot test + asset exporter see a single
92/// flat registry.
93#[must_use]
94pub fn all_stories() -> Vec<Story> {
95 let mut out = Vec::new();
96 out.extend(primitives::stories());
97 out.extend(controls::stories());
98 out.extend(editor::stories());
99 out.extend(shell::stories());
100 out.extend(recorder::stories());
101 out.extend(recorder_display::stories());
102 out.extend(recorder_devices::stories());
103 out.extend(recorder_audio::stories());
104 out.extend(recorder_on_screen::stories());
105 out.extend(recorder_footer::stories());
106 out.extend(save_panel::stories());
107 out.extend(tray_record_popover::stories());
108 out.extend(recording_status::stories());
109 out.extend(fixtures_gallery::stories());
110 // Menus is populated by UI-03 / UI-05; library + cursor land later
111 // (UI-14 / UI-15 / UI-20 / UI-21).
112 out.extend(menus::stories());
113 out.extend(workspace_menu::stories());
114 out.extend(library::stories());
115 out.extend(cursor::stories());
116 out
117}