1use leptos::prelude::*;
5
6use crate::components::shell::{
7 AppSection, AppShell, DropZone, DropZoneState, NavigationRail, StatusBar, StatusKind,
8};
9use crate::fixtures::shell::{sample_nav_items, sample_user_avatar, sample_workspace_badge};
10
11use super::{Story, StoryViewport, render};
12
13#[must_use]
15pub fn stories() -> Vec<Story> {
16 vec![
17 Story {
18 id: "drop-zone-idle",
19 category: "App surfaces",
20 title: "Drop zone — idle",
21 viewport: StoryViewport::Auto,
22 render: render_drop_zone_idle,
23 },
24 Story {
25 id: "drop-zone-active",
26 category: "App surfaces",
27 title: "Drop zone — active (file dragged)",
28 viewport: StoryViewport::Auto,
29 render: render_drop_zone_active,
30 },
31 Story {
32 id: "status-bar-ready",
33 category: "Shell",
34 title: "Status bar — ready",
35 viewport: StoryViewport::Auto,
36 render: render_status_ready,
37 },
38 Story {
39 id: "status-bar-busy",
40 category: "Shell",
41 title: "Status bar — encoding",
42 viewport: StoryViewport::Auto,
43 render: render_status_busy,
44 },
45 Story {
46 id: "status-bar-error",
47 category: "Shell",
48 title: "Status bar — error",
49 viewport: StoryViewport::Auto,
50 render: render_status_error,
51 },
52 Story {
54 id: "nav-rail-record-active",
55 category: "Shell",
56 title: "Nav rail — Record active",
57 viewport: StoryViewport::Fixed {
58 width: 88,
59 height: 460,
60 },
61 render: render_nav_record,
62 },
63 Story {
64 id: "nav-rail-library-active",
65 category: "Shell",
66 title: "Nav rail — Library active",
67 viewport: StoryViewport::Fixed {
68 width: 88,
69 height: 460,
70 },
71 render: render_nav_library,
72 },
73 Story {
74 id: "nav-rail-editor-active",
75 category: "Shell",
76 title: "Nav rail — Editor active",
77 viewport: StoryViewport::Fixed {
78 width: 88,
79 height: 460,
80 },
81 render: render_nav_editor,
82 },
83 Story {
84 id: "nav-rail-cursor-active",
85 category: "Shell",
86 title: "Nav rail — Cursor active",
87 viewport: StoryViewport::Fixed {
88 width: 88,
89 height: 460,
90 },
91 render: render_nav_cursor,
92 },
93 Story {
94 id: "nav-rail-with-counts",
95 category: "Shell",
96 title: "Nav rail — with notification count",
97 viewport: StoryViewport::Fixed {
98 width: 88,
99 height: 460,
100 },
101 render: render_nav_with_counts,
102 },
103 Story {
104 id: "app-shell-three-pane",
105 category: "Compositions",
106 title: "App shell — three-pane editor layout",
107 viewport: StoryViewport::Fixed {
108 width: 760,
109 height: 480,
110 },
111 render: render_app_shell_three_pane,
112 },
113 ]
114}
115
116fn render_drop_zone_idle() -> String {
117 render(view! {
118 <DropZone state=DropZoneState::Idle hint="⌘O to browse" />
119 })
120}
121
122fn render_drop_zone_active() -> String {
123 render(view! {
124 <DropZone state=DropZoneState::Active />
125 })
126}
127
128fn render_status_ready() -> String {
129 render(view! {
130 <StatusBar
131 fps=60.0
132 encoder="H.264 · idle"
133 file_bytes=0
134 kind=StatusKind::Ready
135 />
136 })
137}
138
139fn render_status_busy() -> String {
140 render(view! {
141 <StatusBar
142 fps=60.0
143 encoder="H.264 · 9.4 Mbps"
144 file_bytes=24_117_248_u64
145 kind=StatusKind::Busy
146 detail="Encoding · 38%"
147 />
148 })
149}
150
151fn render_status_error() -> String {
152 render(view! {
153 <StatusBar
154 fps=0.0
155 encoder="H.264"
156 file_bytes=12_582_912_u64
157 kind=StatusKind::Error
158 detail="VideoToolbox: out of memory"
159 />
160 })
161}
162
163fn render_nav_rail(active: AppSection, extra_count: bool) -> String {
164 let workspace = sample_workspace_badge();
165 let user = sample_user_avatar();
166 let items = sample_nav_items(extra_count);
167 render(view! {
168 <div style="width:88px; height:460px; background:#0b0b0d; border:1px solid var(--line-subtle); border-radius:8px;">
169 <NavigationRail items=items active=active workspace=workspace user=user />
170 </div>
171 })
172}
173
174fn render_nav_record() -> String {
175 render_nav_rail(AppSection::Record, false)
176}
177fn render_nav_library() -> String {
178 render_nav_rail(AppSection::Library, false)
179}
180fn render_nav_editor() -> String {
181 render_nav_rail(AppSection::Editor, false)
182}
183fn render_nav_cursor() -> String {
184 render_nav_rail(AppSection::Cursor, false)
185}
186fn render_nav_with_counts() -> String {
187 render_nav_rail(AppSection::Library, true)
188}
189
190fn render_app_shell_three_pane() -> String {
191 let workspace = sample_workspace_badge();
192 let user = sample_user_avatar();
193 let items = sample_nav_items(false);
194 render(view! {
195 <div class="shell-story">
196 <AppShell
197 rail=ToChildren::to_children(move || view! {
198 <NavigationRail
199 items=items
200 active=AppSection::Editor
201 workspace=workspace
202 user=user
203 />
204 })
205 titlebar=ToChildren::to_children(move || view! {
206 <span>"screen-studio · editor · Recording 02"</span>
207 })
208 main=ToChildren::to_children(move || view! {
209 <div class="shell-story-main-placeholder">
210 "Main pane — editor canvas / library grid / cursor preview goes here"
211 </div>
212 })
213 inspector=ToChildren::to_children(move || view! {
214 <div class="shell-story-inspector-placeholder">
215 <h3 style="font-size:13px;margin:0 0 8px;color:var(--text-primary)">"Inspector"</h3>
216 <p>"Property rows render here in UI-18."</p>
217 </div>
218 })
219 footer=ToChildren::to_children(move || view! {
220 <span>"Encoding · 38% · FPS 60"</span>
221 })
222 />
223 </div>
224 })
225}