storybook/stories/
grids.rs1use gpui::{div, prelude::*, px, rgb, Hsla};
2use allui::prelude::*;
3
4pub fn render_grid_story() -> impl IntoElement {
5 VStack::new()
6 .spacing(16.0)
7 .alignment(HorizontalAlignment::Leading)
8 .child(Text::new("Grid - Static 2D table layout:"))
9 .child(
10 VStack::new()
11 .spacing(16.0)
12 .child(Text::new("Data table with GridRow:").foreground_color(Color::gray()))
13 .child(
14 Grid::new()
15 .horizontal_spacing(16.0)
16 .vertical_spacing(8.0)
17 .child(
18 GridRow::new()
19 .child(
20 Text::new("Name")
21 .bold()
22 .foreground_color(Color::secondary_label()),
23 )
24 .child(
25 Text::new("Type")
26 .bold()
27 .foreground_color(Color::secondary_label()),
28 )
29 .child(
30 Text::new("Size")
31 .bold()
32 .foreground_color(Color::secondary_label()),
33 ),
34 )
35 .child(
36 GridRow::new()
37 .child(Text::new("main.rs"))
38 .child(Text::new("Rust"))
39 .child(Text::new("4.2 KB")),
40 )
41 .child(
42 GridRow::new()
43 .child(Text::new("Cargo.toml"))
44 .child(Text::new("TOML"))
45 .child(Text::new("1.1 KB")),
46 )
47 .child(
48 GridRow::new()
49 .child(Text::new("README.md"))
50 .child(Text::new("Markdown"))
51 .child(Text::new("8.7 KB")),
52 )
53 .child(
54 GridRow::new()
55 .child(Text::new("lib.rs"))
56 .child(Text::new("Rust"))
57 .child(Text::new("2.3 KB")),
58 )
59 .padding(16.0)
60 .background(Color::tertiary_system_background())
61 .corner_radius(8.0),
62 )
63 .child(
64 Text::new("Columns auto-size based on content width.")
65 .foreground_color(Color::gray()),
66 ),
67 )
68}
69
70pub fn render_lazy_vgrid_story() -> impl IntoElement {
71 VStack::new()
72 .spacing(16.0)
73 .alignment(HorizontalAlignment::Leading)
74 .child(Text::new(
75 "LazyVGrid - Vertically-scrolling grid with fixed columns:",
76 ))
77 .child(
78 VStack::new()
79 .spacing(8.0)
80 .child(
81 Text::new("Photo gallery mockup (3 columns):").foreground_color(Color::gray()),
82 )
83 .child(
84 ScrollView::new("vgrid-demo")
85 .axes(ScrollAxes::vertical())
86 .child(VStack::new().spacing(8.0).children((0..6).map(|row| {
87 HStack::new().spacing(8.0).children((0..3).map(move |col| {
88 let index = row * 3 + col;
89 let colors = [0x007AFF, 0x34C759, 0xFF9500, 0xFF3B30, 0xAF52DE];
90 let color = colors[index % colors.len()];
91 VStack::new()
92 .child(
93 div().size(px(80.0)).bg(rgb(color as u32)).rounded(px(8.0)),
94 )
95 .child(
96 Text::new(format!("Photo {}", index + 1))
97 .font(Font::caption())
98 .foreground_color(Color::gray()),
99 )
100 .spacing(4.0)
101 }))
102 })))
103 .frame(Frame::size(320.0, 300.0))
104 .background(Color::tertiary_system_background())
105 .corner_radius(8.0),
106 )
107 .child(
108 Text::new("Items flow left-to-right, top-to-bottom. Scroll vertically.")
109 .foreground_color(Color::gray()),
110 )
111 .child(
112 VStack::new()
113 .spacing(4.0)
114 .child(Text::new("Usage:").bold())
115 .child(
116 Text::new(
117 "LazyVGrid::new(cx.entity().clone(), \"id\", &scroll_handle)",
118 )
119 .font(Font::caption())
120 .foreground_color(Color::tertiary_label()),
121 )
122 .child(
123 Text::new(" .columns(vec![GridItem::flexible(); 3])")
124 .font(Font::caption())
125 .foreground_color(Color::tertiary_label()),
126 )
127 .child(
128 Text::new(" .spacing(8.0).item_count(50)")
129 .font(Font::caption())
130 .foreground_color(Color::tertiary_label()),
131 )
132 .child(
133 Text::new(" .render_item(|view, idx, _, _| { ... })")
134 .font(Font::caption())
135 .foreground_color(Color::tertiary_label()),
136 )
137 .child(
138 Text::new(" .build(window, cx)")
139 .font(Font::caption())
140 .foreground_color(Color::tertiary_label()),
141 )
142 .padding(12.0)
143 .background(Color::secondary_system_background())
144 .corner_radius(8.0),
145 ),
146 )
147}
148
149pub fn render_lazy_hgrid_story() -> impl IntoElement {
150 VStack::new()
151 .spacing(16.0)
152 .alignment(HorizontalAlignment::Leading)
153 .child(Text::new(
154 "LazyHGrid - Horizontally-scrolling grid with fixed rows:",
155 ))
156 .child(
157 VStack::new()
158 .spacing(8.0)
159 .child(
160 Text::new("Category carousel mockup (2 rows):").foreground_color(Color::gray()),
161 )
162 .child(
163 ScrollView::new("hgrid-demo")
164 .axes(ScrollAxes::horizontal())
165 .child(HStack::new().spacing(12.0).children((0..8).map(|col| {
166 VStack::new().spacing(12.0).children((0..2).map(move |row| {
167 let index = col * 2 + row;
168 let colors =
169 [0x007AFF, 0x34C759, 0xFF9500, 0xFF3B30, 0xAF52DE, 0x5856D6];
170 let color = colors[index % colors.len()];
171 let categories =
172 ["Music", "Movies", "Books", "Games", "Apps", "Podcasts"];
173 VStack::new()
174 .child(
175 div()
176 .w(px(70.0))
177 .h(px(50.0))
178 .bg(rgb(color as u32))
179 .rounded(px(8.0)),
180 )
181 .child(
182 Text::new(categories[index % categories.len()])
183 .font(Font::caption())
184 .foreground_color(Color::gray()),
185 )
186 .spacing(4.0)
187 }))
188 })))
189 .frame(Frame::size(400.0, 200.0))
190 .background(Color::tertiary_system_background())
191 .corner_radius(8.0),
192 )
193 .child(
194 Text::new("Items flow top-to-bottom, left-to-right. Scroll horizontally.")
195 .foreground_color(Color::gray()),
196 )
197 .child(
198 VStack::new()
199 .spacing(4.0)
200 .child(Text::new("Usage:").bold())
201 .child(
202 Text::new(
203 "LazyHGrid::new(cx.entity().clone(), \"id\", &scroll_handle)",
204 )
205 .font(Font::caption())
206 .foreground_color(Color::tertiary_label()),
207 )
208 .child(
209 Text::new(" .rows(vec![GridItem::fixed(90.0); 2])")
210 .font(Font::caption())
211 .foreground_color(Color::tertiary_label()),
212 )
213 .child(
214 Text::new(" .spacing(12.0).item_count(30)")
215 .font(Font::caption())
216 .foreground_color(Color::tertiary_label()),
217 )
218 .child(
219 Text::new(" .render_item(|view, idx, _, _| { ... })")
220 .font(Font::caption())
221 .foreground_color(Color::tertiary_label()),
222 )
223 .child(
224 Text::new(" .build(window, cx)")
225 .font(Font::caption())
226 .foreground_color(Color::tertiary_label()),
227 )
228 .padding(12.0)
229 .background(Color::secondary_system_background())
230 .corner_radius(8.0),
231 ),
232 )
233}
234
235pub fn render_both_axes_scroll_story(secondary_bg: Hsla) -> impl IntoElement {
236 VStack::new()
237 .spacing(16.0)
238 .alignment(HorizontalAlignment::Leading)
239 .child(Text::new("ScrollView with both axes - Pannable 2D grid:"))
240 .child(
241 VStack::new()
242 .spacing(8.0)
243 .child(
244 Text::new("20x20 coordinate grid (scroll/pan in any direction):")
245 .foreground_color(Color::gray()),
246 )
247 .child(
248 div()
249 .id("both-axes-scroll")
250 .overflow_scroll()
251 .w(px(400.0))
252 .h(px(300.0))
253 .bg(secondary_bg)
254 .rounded(px(8.0))
255 .child(
256 div()
257 .w(px(956.0))
258 .h(px(956.0))
259 .flex()
260 .flex_col()
261 .gap(px(4.0))
262 .children((0..20).map(|row| {
263 div().flex().flex_row().gap(px(4.0)).children((0..20).map(
264 move |col| {
265 let is_origin = row == 0 && col == 0;
266 let is_edge = row == 0 || col == 0;
267 div()
268 .size(px(44.0))
269 .flex()
270 .items_center()
271 .justify_center()
272 .rounded(px(4.0))
273 .bg(rgb(if is_origin {
274 0xFF3B30
275 } else if is_edge {
276 0x555555
277 } else {
278 0x333333
279 }))
280 .text_color(rgb(if is_edge {
281 0xFFFFFF
282 } else {
283 0x888888
284 }))
285 .text_xs()
286 .child(format!("{},{}", col, row))
287 },
288 ))
289 })),
290 ),
291 )
292 .child(
293 Text::new("Red = origin (0,0). Gray headers show row/column indices.")
294 .foreground_color(Color::gray()),
295 ),
296 )
297}