pub trait Modifier: Sized {
Show 21 methods
// Provided methods
fn padding(self, value: impl Into<Padding>) -> Modified<Self> { ... }
fn padding_edges(
self,
top: f32,
leading: f32,
bottom: f32,
trailing: f32,
) -> Modified<Self> { ... }
fn frame(self, frame: Frame) -> Modified<Self> { ... }
fn frame_size(self, width: f32, height: f32) -> Modified<Self> { ... }
fn frame_width(self, width: f32) -> Modified<Self> { ... }
fn frame_height(self, height: f32) -> Modified<Self> { ... }
fn fixed_size(self, horizontal: bool, vertical: bool) -> Modified<Self> { ... }
fn aspect_ratio(
self,
ratio: f32,
content_mode: ContentMode,
) -> Modified<Self> { ... }
fn background(self, color: impl Into<Color>) -> Modified<Self> { ... }
fn foreground_color(self, color: impl Into<Color>) -> Modified<Self> { ... }
fn tint(self, color: impl Into<Color>) -> Modified<Self> { ... }
fn corner_radius(self, radius: f32) -> Modified<Self> { ... }
fn border(self, color: impl Into<Color>, width: f32) -> Modified<Self> { ... }
fn shadow(self, radius: f32) -> Modified<Self> { ... }
fn shadow_with(
self,
radius: f32,
color: impl Into<Color>,
x: f32,
y: f32,
) -> Modified<Self> { ... }
fn opacity(self, value: f32) -> Modified<Self> { ... }
fn hidden(self, is_hidden: bool) -> Modified<Self> { ... }
fn disabled(self, is_disabled: bool) -> Modified<Self> { ... }
fn scale(self, value: f32) -> Modified<Self> { ... }
fn on_tap_gesture(
self,
id: impl Into<SharedString>,
handler: impl Fn() + 'static,
) -> Tappable<Self> { ... }
fn on_tap_gesture_with(
self,
id: impl Into<SharedString>,
handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
) -> Tappable<Self> { ... }
}Expand description
The core modifier trait that all Allui views implement.
This trait provides the SwiftUI-like modifier chain API.
Provided Methods§
Sourcefn padding(self, value: impl Into<Padding>) -> Modified<Self>
fn padding(self, value: impl Into<Padding>) -> Modified<Self>
Add padding around the view.
Examples found in repository?
4pub fn render_vstack_story() -> impl IntoElement {
5 VStack::new()
6 .spacing(16.0)
7 .alignment(HorizontalAlignment::Leading)
8 .child(Text::new(
9 "VStack centers children horizontally by default:",
10 ))
11 .child(
12 VStack::new()
13 .spacing(8.0)
14 .child(Text::new("Child 1").padding(8.0).background(Color::blue()))
15 .child(
16 Text::new("Child 2 (longer)")
17 .padding(8.0)
18 .background(Color::blue()),
19 )
20 .child(Text::new("3").padding(8.0).background(Color::blue()))
21 .padding(16.0)
22 .background(Color::tertiary_system_background())
23 .corner_radius(8.0),
24 )
25 .child(Text::new("VStack with leading alignment:"))
26 .child(
27 VStack::new()
28 .spacing(8.0)
29 .alignment(HorizontalAlignment::Leading)
30 .child(
31 Text::new("Leading 1")
32 .padding(8.0)
33 .background(Color::green()),
34 )
35 .child(
36 Text::new("Leading 2 (longer)")
37 .padding(8.0)
38 .background(Color::green()),
39 )
40 .padding(16.0)
41 .background(Color::tertiary_system_background())
42 .corner_radius(8.0),
43 )
44}
45
46pub fn render_hstack_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("HStack centers children vertically by default:"))
51 .child(
52 HStack::new()
53 .spacing(8.0)
54 .child(Text::new("A").padding(8.0).background(Color::blue()))
55 .child(
56 Text::new("Tall")
57 .padding_edges(8.0, 8.0, 32.0, 8.0)
58 .background(Color::blue()),
59 )
60 .child(Text::new("C").padding(8.0).background(Color::blue()))
61 .padding(16.0)
62 .background(Color::tertiary_system_background())
63 .corner_radius(8.0),
64 )
65 .child(Text::new("HStack with top alignment:"))
66 .child(
67 HStack::new()
68 .spacing(8.0)
69 .alignment(VerticalAlignment::Top)
70 .child(Text::new("Top").padding(8.0).background(Color::green()))
71 .child(
72 Text::new("Aligned")
73 .padding_edges(8.0, 8.0, 32.0, 8.0)
74 .background(Color::green()),
75 )
76 .padding(16.0)
77 .background(Color::tertiary_system_background())
78 .corner_radius(8.0),
79 )
80}
81
82pub fn render_zstack_story() -> impl IntoElement {
83 VStack::new()
84 .spacing(16.0)
85 .alignment(HorizontalAlignment::Leading)
86 .child(Text::new("ZStack overlays children, centered by default:"))
87 .child(
88 ZStack::new()
89 .child(div().size(px(150.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
90 .child(div().size(px(80.0)).bg(rgb(0xFF3B30)).rounded_full())
91 .frame_size(200.0, 200.0)
92 .background(Color::tertiary_system_background())
93 .corner_radius(8.0),
94 )
95}
96
97pub fn render_spacer_story() -> impl IntoElement {
98 VStack::new()
99 .spacing(16.0)
100 .alignment(HorizontalAlignment::Leading)
101 .child(Text::new("Spacer pushes content to edges:"))
102 .child(
103 HStack::new()
104 .child(Text::new("Left").padding(8.0).background(Color::blue()))
105 .child(Spacer::new())
106 .child(Text::new("Right").padding(8.0).background(Color::blue()))
107 .padding(16.0)
108 .background(Color::tertiary_system_background())
109 .corner_radius(8.0)
110 .frame_width(400.0),
111 )
112 .child(Text::new("Multiple spacers distribute evenly:"))
113 .child(
114 HStack::new()
115 .child(Spacer::new())
116 .child(Text::new("Center").padding(8.0).background(Color::green()))
117 .child(Spacer::new())
118 .padding(16.0)
119 .background(Color::tertiary_system_background())
120 .corner_radius(8.0)
121 .frame_width(400.0),
122 )
123}More examples
6pub fn render_scrollview_story() -> impl IntoElement {
7 VStack::new()
8 .spacing(16.0)
9 .alignment(HorizontalAlignment::Leading)
10 .child(Text::new("ScrollView - Scrollable container for content:"))
11 .child(
12 VStack::new()
13 .spacing(16.0)
14 .child(Text::new("Vertical scroll (default):"))
15 .child(
16 ScrollView::new("vertical-scroll")
17 .axes(ScrollAxes::vertical())
18 .child(VStack::new().spacing(8.0).children((1..=20).map(|i| {
19 Text::new(format!("Item {}", i))
20 .padding(12.0)
21 .background(Color::tertiary_system_background())
22 .corner_radius(4.0)
23 })))
24 .frame(Frame::size(300.0, 200.0))
25 .background(Color::tertiary_system_background())
26 .corner_radius(8.0),
27 )
28 .child(Text::new("Horizontal scroll:"))
29 .child(
30 ScrollView::new("horizontal-scroll")
31 .axes(ScrollAxes::horizontal())
32 .child(HStack::new().spacing(8.0).children((1..=15).map(|i| {
33 VStack::new()
34 .child(div().size(px(60.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
35 .child(Text::new(format!("{}", i)))
36 .spacing(4.0)
37 .padding(8.0)
38 })))
39 .frame(Frame::size(400.0, 120.0))
40 .background(Color::tertiary_system_background())
41 .corner_radius(8.0),
42 ),
43 )
44}
45
46pub fn render_list_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("List & Section - iOS-style grouped lists:"))
51 .child(
52 HStack::new()
53 .spacing(24.0)
54 .alignment(VerticalAlignment::Top)
55 .child(
56 VStack::new()
57 .spacing(8.0)
58 .child(Text::new("Inset Grouped (Dark):").foreground_color(Color::gray()))
59 .child(
60 List::new("settings-list")
61 .list_style(ListStyle::inset_grouped())
62 .child(
63 Section::new()
64 .header("Account")
65 .child(Text::new("Profile"))
66 .child(Text::new("Privacy"))
67 .child(Text::new("Security")),
68 )
69 .child(
70 Section::new()
71 .header("Preferences")
72 .footer("Customize your experience")
73 .child(Text::new("Notifications"))
74 .child(Text::new("Appearance"))
75 .child(Text::new("Language")),
76 )
77 .frame(Frame::size(280.0, 380.0))
78 .background(Color::system_background())
79 .corner_radius(12.0),
80 ),
81 )
82 .child(
83 VStack::new()
84 .spacing(8.0)
85 .child(Text::new("Plain (Dark):").foreground_color(Color::gray()))
86 .child(
87 List::new("plain-list")
88 .list_style(ListStyle::plain())
89 .child(
90 Section::new()
91 .child(Text::new("First Item"))
92 .child(Text::new("Second Item"))
93 .child(Text::new("Third Item")),
94 )
95 .frame(Frame::size(200.0, 200.0))
96 .background(Color::system_background())
97 .corner_radius(8.0),
98 ),
99 ),
100 )
101}
102
103pub fn render_foreach_story() -> impl IntoElement {
104 let fruits = vec!["Apple", "Banana", "Cherry", "Date", "Elderberry"];
105 let numbers = vec![1, 2, 3, 4, 5];
106
107 VStack::new()
108 .spacing(16.0)
109 .alignment(HorizontalAlignment::Leading)
110 .child(Text::new("ForEach - Iterate over collections:"))
111 .child(
112 HStack::new()
113 .spacing(32.0)
114 .alignment(VerticalAlignment::Top)
115 .child(
116 VStack::new()
117 .spacing(8.0)
118 .child(Text::new("String list:").foreground_color(Color::gray()))
119 .child(
120 VStack::new()
121 .spacing(4.0)
122 .children(ForEach::new(fruits, |fruit| {
123 HStack::new()
124 .spacing(8.0)
125 .child(div().size(px(8.0)).bg(rgb(0x34C759)).rounded_full())
126 .child(Text::new(*fruit))
127 }))
128 .padding(16.0)
129 .background(Color::tertiary_system_background())
130 .corner_radius(8.0),
131 ),
132 )
133 .child(
134 VStack::new()
135 .spacing(8.0)
136 .child(Text::new("Number grid:").foreground_color(Color::gray()))
137 .child(
138 HStack::new()
139 .spacing(8.0)
140 .children(ForEach::new(numbers, |num| {
141 Text::new(format!("{}", num))
142 .padding(16.0)
143 .background(Color::blue())
144 .corner_radius(8.0)
145 }))
146 .padding(16.0)
147 .background(Color::tertiary_system_background())
148 .corner_radius(8.0),
149 ),
150 ),
151 )
152 .child(
153 Text::new("ForEach works with VStack.children(), HStack.children(), etc.")
154 .foreground_color(Color::gray()),
155 )
156}
157
158pub fn render_conditional_story(
159 storybook: &Storybook,
160 cx: &mut Context<Storybook>,
161) -> impl IntoElement {
162 let show_content = storybook.show_content;
163 let selected_fruit = storybook.selected_fruit;
164 let entity = cx.entity().clone();
165 let entity2 = cx.entity().clone();
166
167 let fruits = ["Apple", "Banana", "Cherry"];
168
169 VStack::new()
170 .spacing(16.0)
171 .alignment(HorizontalAlignment::Leading)
172 .child(Text::new("If - Conditional rendering:"))
173 .child(
174 VStack::new()
175 .spacing(12.0)
176 .child(HStack::new().spacing(12.0).child(Toggle::new_with_handler(
177 "Show Content",
178 show_content,
179 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
180 this.show_content = *checked;
181 cx.notify();
182 }),
183 )))
184 .child(
185 If::new(show_content)
186 .then(|| {
187 Text::new("Content is visible!")
188 .padding(16.0)
189 .background(Color::green())
190 .corner_radius(8.0)
191 })
192 .otherwise(|| {
193 Text::new("Content is hidden")
194 .padding(16.0)
195 .background(Color::red())
196 .corner_radius(8.0)
197 }),
198 )
199 .padding(16.0)
200 .background(Color::tertiary_system_background())
201 .corner_radius(8.0),
202 )
203 .child(Text::new("IfLet - Render when Option is Some:"))
204 .child(
205 VStack::new()
206 .spacing(12.0)
207 .child(
208 HStack::new()
209 .spacing(8.0)
210 .children(fruits.iter().enumerate().map(|(idx, fruit)| {
211 let is_selected = selected_fruit == Some(idx);
212 let entity = entity.clone();
213 Text::new(*fruit)
214 .padding(8.0)
215 .background(if is_selected {
216 Color::blue()
217 } else {
218 Color::secondary()
219 })
220 .corner_radius(4.0)
221 .on_tap_gesture_with(
222 SharedString::from(format!("fruit-{}", idx)),
223 move |_, _, cx| {
224 entity.update(cx, |this, cx| {
225 this.selected_fruit = Some(idx);
226 cx.notify();
227 });
228 },
229 )
230 }))
231 .child(
232 Text::new("None")
233 .padding(8.0)
234 .background(if selected_fruit.is_none() {
235 Color::blue()
236 } else {
237 Color::secondary()
238 })
239 .corner_radius(4.0)
240 .on_tap_gesture_with("fruit-none", move |_, _, cx| {
241 entity2.update(cx, |this, cx| {
242 this.selected_fruit = None;
243 cx.notify();
244 });
245 }),
246 ),
247 )
248 .child(IfLet::new(selected_fruit, move |idx| {
249 let fruit_names = ["Apple", "Banana", "Cherry"];
250 Text::new(format!("Selected: {} (index {})", fruit_names[*idx], idx))
251 .padding(12.0)
252 .background(Color::green())
253 .corner_radius(8.0)
254 }))
255 .child(
256 If::new(selected_fruit.is_none())
257 .then(|| {
258 Text::new("No fruit selected")
259 .padding(12.0)
260 .foreground_color(Color::gray())
261 })
262 .otherwise(EmptyView::new),
263 )
264 .padding(16.0)
265 .background(Color::tertiary_system_background())
266 .corner_radius(8.0),
267 )
268}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}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}Sourcefn padding_edges(
self,
top: f32,
leading: f32,
bottom: f32,
trailing: f32,
) -> Modified<Self>
fn padding_edges( self, top: f32, leading: f32, bottom: f32, trailing: f32, ) -> Modified<Self>
Add padding to specific edges.
Examples found in repository?
46pub fn render_hstack_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("HStack centers children vertically by default:"))
51 .child(
52 HStack::new()
53 .spacing(8.0)
54 .child(Text::new("A").padding(8.0).background(Color::blue()))
55 .child(
56 Text::new("Tall")
57 .padding_edges(8.0, 8.0, 32.0, 8.0)
58 .background(Color::blue()),
59 )
60 .child(Text::new("C").padding(8.0).background(Color::blue()))
61 .padding(16.0)
62 .background(Color::tertiary_system_background())
63 .corner_radius(8.0),
64 )
65 .child(Text::new("HStack with top alignment:"))
66 .child(
67 HStack::new()
68 .spacing(8.0)
69 .alignment(VerticalAlignment::Top)
70 .child(Text::new("Top").padding(8.0).background(Color::green()))
71 .child(
72 Text::new("Aligned")
73 .padding_edges(8.0, 8.0, 32.0, 8.0)
74 .background(Color::green()),
75 )
76 .padding(16.0)
77 .background(Color::tertiary_system_background())
78 .corner_radius(8.0),
79 )
80}Sourcefn frame(self, frame: Frame) -> Modified<Self>
fn frame(self, frame: Frame) -> Modified<Self>
Apply a frame with the specified configuration.
§Examples
// Fixed dimensions
Text::new("Hello").frame(Frame::size(100.0, 50.0))
// Just width
Text::new("Hello").frame(Frame::width(200.0))
// Fill available width
Text::new("Hello").frame(Frame::fill_width())
// Flexible constraints
Text::new("Hello").frame(Frame::new().min_width(100.0).max_width(300.0))Examples found in repository?
6pub fn render_scrollview_story() -> impl IntoElement {
7 VStack::new()
8 .spacing(16.0)
9 .alignment(HorizontalAlignment::Leading)
10 .child(Text::new("ScrollView - Scrollable container for content:"))
11 .child(
12 VStack::new()
13 .spacing(16.0)
14 .child(Text::new("Vertical scroll (default):"))
15 .child(
16 ScrollView::new("vertical-scroll")
17 .axes(ScrollAxes::vertical())
18 .child(VStack::new().spacing(8.0).children((1..=20).map(|i| {
19 Text::new(format!("Item {}", i))
20 .padding(12.0)
21 .background(Color::tertiary_system_background())
22 .corner_radius(4.0)
23 })))
24 .frame(Frame::size(300.0, 200.0))
25 .background(Color::tertiary_system_background())
26 .corner_radius(8.0),
27 )
28 .child(Text::new("Horizontal scroll:"))
29 .child(
30 ScrollView::new("horizontal-scroll")
31 .axes(ScrollAxes::horizontal())
32 .child(HStack::new().spacing(8.0).children((1..=15).map(|i| {
33 VStack::new()
34 .child(div().size(px(60.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
35 .child(Text::new(format!("{}", i)))
36 .spacing(4.0)
37 .padding(8.0)
38 })))
39 .frame(Frame::size(400.0, 120.0))
40 .background(Color::tertiary_system_background())
41 .corner_radius(8.0),
42 ),
43 )
44}
45
46pub fn render_list_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("List & Section - iOS-style grouped lists:"))
51 .child(
52 HStack::new()
53 .spacing(24.0)
54 .alignment(VerticalAlignment::Top)
55 .child(
56 VStack::new()
57 .spacing(8.0)
58 .child(Text::new("Inset Grouped (Dark):").foreground_color(Color::gray()))
59 .child(
60 List::new("settings-list")
61 .list_style(ListStyle::inset_grouped())
62 .child(
63 Section::new()
64 .header("Account")
65 .child(Text::new("Profile"))
66 .child(Text::new("Privacy"))
67 .child(Text::new("Security")),
68 )
69 .child(
70 Section::new()
71 .header("Preferences")
72 .footer("Customize your experience")
73 .child(Text::new("Notifications"))
74 .child(Text::new("Appearance"))
75 .child(Text::new("Language")),
76 )
77 .frame(Frame::size(280.0, 380.0))
78 .background(Color::system_background())
79 .corner_radius(12.0),
80 ),
81 )
82 .child(
83 VStack::new()
84 .spacing(8.0)
85 .child(Text::new("Plain (Dark):").foreground_color(Color::gray()))
86 .child(
87 List::new("plain-list")
88 .list_style(ListStyle::plain())
89 .child(
90 Section::new()
91 .child(Text::new("First Item"))
92 .child(Text::new("Second Item"))
93 .child(Text::new("Third Item")),
94 )
95 .frame(Frame::size(200.0, 200.0))
96 .background(Color::system_background())
97 .corner_radius(8.0),
98 ),
99 ),
100 )
101}More examples
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}Sourcefn frame_size(self, width: f32, height: f32) -> Modified<Self>
fn frame_size(self, width: f32, height: f32) -> Modified<Self>
Set fixed width and height. Shorthand for frame(Frame::size(w, h)).
Examples found in repository?
82pub fn render_zstack_story() -> impl IntoElement {
83 VStack::new()
84 .spacing(16.0)
85 .alignment(HorizontalAlignment::Leading)
86 .child(Text::new("ZStack overlays children, centered by default:"))
87 .child(
88 ZStack::new()
89 .child(div().size(px(150.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
90 .child(div().size(px(80.0)).bg(rgb(0xFF3B30)).rounded_full())
91 .frame_size(200.0, 200.0)
92 .background(Color::tertiary_system_background())
93 .corner_radius(8.0),
94 )
95}More examples
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}Sourcefn frame_width(self, width: f32) -> Modified<Self>
fn frame_width(self, width: f32) -> Modified<Self>
Set fixed width only. Shorthand for frame(Frame::width(w)).
Examples found in repository?
97pub fn render_spacer_story() -> impl IntoElement {
98 VStack::new()
99 .spacing(16.0)
100 .alignment(HorizontalAlignment::Leading)
101 .child(Text::new("Spacer pushes content to edges:"))
102 .child(
103 HStack::new()
104 .child(Text::new("Left").padding(8.0).background(Color::blue()))
105 .child(Spacer::new())
106 .child(Text::new("Right").padding(8.0).background(Color::blue()))
107 .padding(16.0)
108 .background(Color::tertiary_system_background())
109 .corner_radius(8.0)
110 .frame_width(400.0),
111 )
112 .child(Text::new("Multiple spacers distribute evenly:"))
113 .child(
114 HStack::new()
115 .child(Spacer::new())
116 .child(Text::new("Center").padding(8.0).background(Color::green()))
117 .child(Spacer::new())
118 .padding(16.0)
119 .background(Color::tertiary_system_background())
120 .corner_radius(8.0)
121 .frame_width(400.0),
122 )
123}More examples
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}Sourcefn frame_height(self, height: f32) -> Modified<Self>
fn frame_height(self, height: f32) -> Modified<Self>
Set fixed height only. Shorthand for frame(Frame::height(h)).
Sourcefn fixed_size(self, horizontal: bool, vertical: bool) -> Modified<Self>
fn fixed_size(self, horizontal: bool, vertical: bool) -> Modified<Self>
Prevent the view from expanding beyond its ideal size.
Sourcefn aspect_ratio(self, ratio: f32, content_mode: ContentMode) -> Modified<Self>
fn aspect_ratio(self, ratio: f32, content_mode: ContentMode) -> Modified<Self>
Constrain the view to a specific aspect ratio.
Sourcefn background(self, color: impl Into<Color>) -> Modified<Self>
fn background(self, color: impl Into<Color>) -> Modified<Self>
Set the background color.
Examples found in repository?
4pub fn render_vstack_story() -> impl IntoElement {
5 VStack::new()
6 .spacing(16.0)
7 .alignment(HorizontalAlignment::Leading)
8 .child(Text::new(
9 "VStack centers children horizontally by default:",
10 ))
11 .child(
12 VStack::new()
13 .spacing(8.0)
14 .child(Text::new("Child 1").padding(8.0).background(Color::blue()))
15 .child(
16 Text::new("Child 2 (longer)")
17 .padding(8.0)
18 .background(Color::blue()),
19 )
20 .child(Text::new("3").padding(8.0).background(Color::blue()))
21 .padding(16.0)
22 .background(Color::tertiary_system_background())
23 .corner_radius(8.0),
24 )
25 .child(Text::new("VStack with leading alignment:"))
26 .child(
27 VStack::new()
28 .spacing(8.0)
29 .alignment(HorizontalAlignment::Leading)
30 .child(
31 Text::new("Leading 1")
32 .padding(8.0)
33 .background(Color::green()),
34 )
35 .child(
36 Text::new("Leading 2 (longer)")
37 .padding(8.0)
38 .background(Color::green()),
39 )
40 .padding(16.0)
41 .background(Color::tertiary_system_background())
42 .corner_radius(8.0),
43 )
44}
45
46pub fn render_hstack_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("HStack centers children vertically by default:"))
51 .child(
52 HStack::new()
53 .spacing(8.0)
54 .child(Text::new("A").padding(8.0).background(Color::blue()))
55 .child(
56 Text::new("Tall")
57 .padding_edges(8.0, 8.0, 32.0, 8.0)
58 .background(Color::blue()),
59 )
60 .child(Text::new("C").padding(8.0).background(Color::blue()))
61 .padding(16.0)
62 .background(Color::tertiary_system_background())
63 .corner_radius(8.0),
64 )
65 .child(Text::new("HStack with top alignment:"))
66 .child(
67 HStack::new()
68 .spacing(8.0)
69 .alignment(VerticalAlignment::Top)
70 .child(Text::new("Top").padding(8.0).background(Color::green()))
71 .child(
72 Text::new("Aligned")
73 .padding_edges(8.0, 8.0, 32.0, 8.0)
74 .background(Color::green()),
75 )
76 .padding(16.0)
77 .background(Color::tertiary_system_background())
78 .corner_radius(8.0),
79 )
80}
81
82pub fn render_zstack_story() -> impl IntoElement {
83 VStack::new()
84 .spacing(16.0)
85 .alignment(HorizontalAlignment::Leading)
86 .child(Text::new("ZStack overlays children, centered by default:"))
87 .child(
88 ZStack::new()
89 .child(div().size(px(150.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
90 .child(div().size(px(80.0)).bg(rgb(0xFF3B30)).rounded_full())
91 .frame_size(200.0, 200.0)
92 .background(Color::tertiary_system_background())
93 .corner_radius(8.0),
94 )
95}
96
97pub fn render_spacer_story() -> impl IntoElement {
98 VStack::new()
99 .spacing(16.0)
100 .alignment(HorizontalAlignment::Leading)
101 .child(Text::new("Spacer pushes content to edges:"))
102 .child(
103 HStack::new()
104 .child(Text::new("Left").padding(8.0).background(Color::blue()))
105 .child(Spacer::new())
106 .child(Text::new("Right").padding(8.0).background(Color::blue()))
107 .padding(16.0)
108 .background(Color::tertiary_system_background())
109 .corner_radius(8.0)
110 .frame_width(400.0),
111 )
112 .child(Text::new("Multiple spacers distribute evenly:"))
113 .child(
114 HStack::new()
115 .child(Spacer::new())
116 .child(Text::new("Center").padding(8.0).background(Color::green()))
117 .child(Spacer::new())
118 .padding(16.0)
119 .background(Color::tertiary_system_background())
120 .corner_radius(8.0)
121 .frame_width(400.0),
122 )
123}More examples
6pub fn render_scrollview_story() -> impl IntoElement {
7 VStack::new()
8 .spacing(16.0)
9 .alignment(HorizontalAlignment::Leading)
10 .child(Text::new("ScrollView - Scrollable container for content:"))
11 .child(
12 VStack::new()
13 .spacing(16.0)
14 .child(Text::new("Vertical scroll (default):"))
15 .child(
16 ScrollView::new("vertical-scroll")
17 .axes(ScrollAxes::vertical())
18 .child(VStack::new().spacing(8.0).children((1..=20).map(|i| {
19 Text::new(format!("Item {}", i))
20 .padding(12.0)
21 .background(Color::tertiary_system_background())
22 .corner_radius(4.0)
23 })))
24 .frame(Frame::size(300.0, 200.0))
25 .background(Color::tertiary_system_background())
26 .corner_radius(8.0),
27 )
28 .child(Text::new("Horizontal scroll:"))
29 .child(
30 ScrollView::new("horizontal-scroll")
31 .axes(ScrollAxes::horizontal())
32 .child(HStack::new().spacing(8.0).children((1..=15).map(|i| {
33 VStack::new()
34 .child(div().size(px(60.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
35 .child(Text::new(format!("{}", i)))
36 .spacing(4.0)
37 .padding(8.0)
38 })))
39 .frame(Frame::size(400.0, 120.0))
40 .background(Color::tertiary_system_background())
41 .corner_radius(8.0),
42 ),
43 )
44}
45
46pub fn render_list_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("List & Section - iOS-style grouped lists:"))
51 .child(
52 HStack::new()
53 .spacing(24.0)
54 .alignment(VerticalAlignment::Top)
55 .child(
56 VStack::new()
57 .spacing(8.0)
58 .child(Text::new("Inset Grouped (Dark):").foreground_color(Color::gray()))
59 .child(
60 List::new("settings-list")
61 .list_style(ListStyle::inset_grouped())
62 .child(
63 Section::new()
64 .header("Account")
65 .child(Text::new("Profile"))
66 .child(Text::new("Privacy"))
67 .child(Text::new("Security")),
68 )
69 .child(
70 Section::new()
71 .header("Preferences")
72 .footer("Customize your experience")
73 .child(Text::new("Notifications"))
74 .child(Text::new("Appearance"))
75 .child(Text::new("Language")),
76 )
77 .frame(Frame::size(280.0, 380.0))
78 .background(Color::system_background())
79 .corner_radius(12.0),
80 ),
81 )
82 .child(
83 VStack::new()
84 .spacing(8.0)
85 .child(Text::new("Plain (Dark):").foreground_color(Color::gray()))
86 .child(
87 List::new("plain-list")
88 .list_style(ListStyle::plain())
89 .child(
90 Section::new()
91 .child(Text::new("First Item"))
92 .child(Text::new("Second Item"))
93 .child(Text::new("Third Item")),
94 )
95 .frame(Frame::size(200.0, 200.0))
96 .background(Color::system_background())
97 .corner_radius(8.0),
98 ),
99 ),
100 )
101}
102
103pub fn render_foreach_story() -> impl IntoElement {
104 let fruits = vec!["Apple", "Banana", "Cherry", "Date", "Elderberry"];
105 let numbers = vec![1, 2, 3, 4, 5];
106
107 VStack::new()
108 .spacing(16.0)
109 .alignment(HorizontalAlignment::Leading)
110 .child(Text::new("ForEach - Iterate over collections:"))
111 .child(
112 HStack::new()
113 .spacing(32.0)
114 .alignment(VerticalAlignment::Top)
115 .child(
116 VStack::new()
117 .spacing(8.0)
118 .child(Text::new("String list:").foreground_color(Color::gray()))
119 .child(
120 VStack::new()
121 .spacing(4.0)
122 .children(ForEach::new(fruits, |fruit| {
123 HStack::new()
124 .spacing(8.0)
125 .child(div().size(px(8.0)).bg(rgb(0x34C759)).rounded_full())
126 .child(Text::new(*fruit))
127 }))
128 .padding(16.0)
129 .background(Color::tertiary_system_background())
130 .corner_radius(8.0),
131 ),
132 )
133 .child(
134 VStack::new()
135 .spacing(8.0)
136 .child(Text::new("Number grid:").foreground_color(Color::gray()))
137 .child(
138 HStack::new()
139 .spacing(8.0)
140 .children(ForEach::new(numbers, |num| {
141 Text::new(format!("{}", num))
142 .padding(16.0)
143 .background(Color::blue())
144 .corner_radius(8.0)
145 }))
146 .padding(16.0)
147 .background(Color::tertiary_system_background())
148 .corner_radius(8.0),
149 ),
150 ),
151 )
152 .child(
153 Text::new("ForEach works with VStack.children(), HStack.children(), etc.")
154 .foreground_color(Color::gray()),
155 )
156}
157
158pub fn render_conditional_story(
159 storybook: &Storybook,
160 cx: &mut Context<Storybook>,
161) -> impl IntoElement {
162 let show_content = storybook.show_content;
163 let selected_fruit = storybook.selected_fruit;
164 let entity = cx.entity().clone();
165 let entity2 = cx.entity().clone();
166
167 let fruits = ["Apple", "Banana", "Cherry"];
168
169 VStack::new()
170 .spacing(16.0)
171 .alignment(HorizontalAlignment::Leading)
172 .child(Text::new("If - Conditional rendering:"))
173 .child(
174 VStack::new()
175 .spacing(12.0)
176 .child(HStack::new().spacing(12.0).child(Toggle::new_with_handler(
177 "Show Content",
178 show_content,
179 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
180 this.show_content = *checked;
181 cx.notify();
182 }),
183 )))
184 .child(
185 If::new(show_content)
186 .then(|| {
187 Text::new("Content is visible!")
188 .padding(16.0)
189 .background(Color::green())
190 .corner_radius(8.0)
191 })
192 .otherwise(|| {
193 Text::new("Content is hidden")
194 .padding(16.0)
195 .background(Color::red())
196 .corner_radius(8.0)
197 }),
198 )
199 .padding(16.0)
200 .background(Color::tertiary_system_background())
201 .corner_radius(8.0),
202 )
203 .child(Text::new("IfLet - Render when Option is Some:"))
204 .child(
205 VStack::new()
206 .spacing(12.0)
207 .child(
208 HStack::new()
209 .spacing(8.0)
210 .children(fruits.iter().enumerate().map(|(idx, fruit)| {
211 let is_selected = selected_fruit == Some(idx);
212 let entity = entity.clone();
213 Text::new(*fruit)
214 .padding(8.0)
215 .background(if is_selected {
216 Color::blue()
217 } else {
218 Color::secondary()
219 })
220 .corner_radius(4.0)
221 .on_tap_gesture_with(
222 SharedString::from(format!("fruit-{}", idx)),
223 move |_, _, cx| {
224 entity.update(cx, |this, cx| {
225 this.selected_fruit = Some(idx);
226 cx.notify();
227 });
228 },
229 )
230 }))
231 .child(
232 Text::new("None")
233 .padding(8.0)
234 .background(if selected_fruit.is_none() {
235 Color::blue()
236 } else {
237 Color::secondary()
238 })
239 .corner_radius(4.0)
240 .on_tap_gesture_with("fruit-none", move |_, _, cx| {
241 entity2.update(cx, |this, cx| {
242 this.selected_fruit = None;
243 cx.notify();
244 });
245 }),
246 ),
247 )
248 .child(IfLet::new(selected_fruit, move |idx| {
249 let fruit_names = ["Apple", "Banana", "Cherry"];
250 Text::new(format!("Selected: {} (index {})", fruit_names[*idx], idx))
251 .padding(12.0)
252 .background(Color::green())
253 .corner_radius(8.0)
254 }))
255 .child(
256 If::new(selected_fruit.is_none())
257 .then(|| {
258 Text::new("No fruit selected")
259 .padding(12.0)
260 .foreground_color(Color::gray())
261 })
262 .otherwise(EmptyView::new),
263 )
264 .padding(16.0)
265 .background(Color::tertiary_system_background())
266 .corner_radius(8.0),
267 )
268}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}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}Sourcefn foreground_color(self, color: impl Into<Color>) -> Modified<Self>
fn foreground_color(self, color: impl Into<Color>) -> Modified<Self>
Set the foreground (text) color.
Examples found in repository?
158pub fn render_conditional_story(
159 storybook: &Storybook,
160 cx: &mut Context<Storybook>,
161) -> impl IntoElement {
162 let show_content = storybook.show_content;
163 let selected_fruit = storybook.selected_fruit;
164 let entity = cx.entity().clone();
165 let entity2 = cx.entity().clone();
166
167 let fruits = ["Apple", "Banana", "Cherry"];
168
169 VStack::new()
170 .spacing(16.0)
171 .alignment(HorizontalAlignment::Leading)
172 .child(Text::new("If - Conditional rendering:"))
173 .child(
174 VStack::new()
175 .spacing(12.0)
176 .child(HStack::new().spacing(12.0).child(Toggle::new_with_handler(
177 "Show Content",
178 show_content,
179 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
180 this.show_content = *checked;
181 cx.notify();
182 }),
183 )))
184 .child(
185 If::new(show_content)
186 .then(|| {
187 Text::new("Content is visible!")
188 .padding(16.0)
189 .background(Color::green())
190 .corner_radius(8.0)
191 })
192 .otherwise(|| {
193 Text::new("Content is hidden")
194 .padding(16.0)
195 .background(Color::red())
196 .corner_radius(8.0)
197 }),
198 )
199 .padding(16.0)
200 .background(Color::tertiary_system_background())
201 .corner_radius(8.0),
202 )
203 .child(Text::new("IfLet - Render when Option is Some:"))
204 .child(
205 VStack::new()
206 .spacing(12.0)
207 .child(
208 HStack::new()
209 .spacing(8.0)
210 .children(fruits.iter().enumerate().map(|(idx, fruit)| {
211 let is_selected = selected_fruit == Some(idx);
212 let entity = entity.clone();
213 Text::new(*fruit)
214 .padding(8.0)
215 .background(if is_selected {
216 Color::blue()
217 } else {
218 Color::secondary()
219 })
220 .corner_radius(4.0)
221 .on_tap_gesture_with(
222 SharedString::from(format!("fruit-{}", idx)),
223 move |_, _, cx| {
224 entity.update(cx, |this, cx| {
225 this.selected_fruit = Some(idx);
226 cx.notify();
227 });
228 },
229 )
230 }))
231 .child(
232 Text::new("None")
233 .padding(8.0)
234 .background(if selected_fruit.is_none() {
235 Color::blue()
236 } else {
237 Color::secondary()
238 })
239 .corner_radius(4.0)
240 .on_tap_gesture_with("fruit-none", move |_, _, cx| {
241 entity2.update(cx, |this, cx| {
242 this.selected_fruit = None;
243 cx.notify();
244 });
245 }),
246 ),
247 )
248 .child(IfLet::new(selected_fruit, move |idx| {
249 let fruit_names = ["Apple", "Banana", "Cherry"];
250 Text::new(format!("Selected: {} (index {})", fruit_names[*idx], idx))
251 .padding(12.0)
252 .background(Color::green())
253 .corner_radius(8.0)
254 }))
255 .child(
256 If::new(selected_fruit.is_none())
257 .then(|| {
258 Text::new("No fruit selected")
259 .padding(12.0)
260 .foreground_color(Color::gray())
261 })
262 .otherwise(EmptyView::new),
263 )
264 .padding(16.0)
265 .background(Color::tertiary_system_background())
266 .corner_radius(8.0),
267 )
268}Sourcefn tint(self, color: impl Into<Color>) -> Modified<Self>
fn tint(self, color: impl Into<Color>) -> Modified<Self>
Set the tint color for interactive elements.
Sourcefn corner_radius(self, radius: f32) -> Modified<Self>
fn corner_radius(self, radius: f32) -> Modified<Self>
Round the corners.
Examples found in repository?
4pub fn render_vstack_story() -> impl IntoElement {
5 VStack::new()
6 .spacing(16.0)
7 .alignment(HorizontalAlignment::Leading)
8 .child(Text::new(
9 "VStack centers children horizontally by default:",
10 ))
11 .child(
12 VStack::new()
13 .spacing(8.0)
14 .child(Text::new("Child 1").padding(8.0).background(Color::blue()))
15 .child(
16 Text::new("Child 2 (longer)")
17 .padding(8.0)
18 .background(Color::blue()),
19 )
20 .child(Text::new("3").padding(8.0).background(Color::blue()))
21 .padding(16.0)
22 .background(Color::tertiary_system_background())
23 .corner_radius(8.0),
24 )
25 .child(Text::new("VStack with leading alignment:"))
26 .child(
27 VStack::new()
28 .spacing(8.0)
29 .alignment(HorizontalAlignment::Leading)
30 .child(
31 Text::new("Leading 1")
32 .padding(8.0)
33 .background(Color::green()),
34 )
35 .child(
36 Text::new("Leading 2 (longer)")
37 .padding(8.0)
38 .background(Color::green()),
39 )
40 .padding(16.0)
41 .background(Color::tertiary_system_background())
42 .corner_radius(8.0),
43 )
44}
45
46pub fn render_hstack_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("HStack centers children vertically by default:"))
51 .child(
52 HStack::new()
53 .spacing(8.0)
54 .child(Text::new("A").padding(8.0).background(Color::blue()))
55 .child(
56 Text::new("Tall")
57 .padding_edges(8.0, 8.0, 32.0, 8.0)
58 .background(Color::blue()),
59 )
60 .child(Text::new("C").padding(8.0).background(Color::blue()))
61 .padding(16.0)
62 .background(Color::tertiary_system_background())
63 .corner_radius(8.0),
64 )
65 .child(Text::new("HStack with top alignment:"))
66 .child(
67 HStack::new()
68 .spacing(8.0)
69 .alignment(VerticalAlignment::Top)
70 .child(Text::new("Top").padding(8.0).background(Color::green()))
71 .child(
72 Text::new("Aligned")
73 .padding_edges(8.0, 8.0, 32.0, 8.0)
74 .background(Color::green()),
75 )
76 .padding(16.0)
77 .background(Color::tertiary_system_background())
78 .corner_radius(8.0),
79 )
80}
81
82pub fn render_zstack_story() -> impl IntoElement {
83 VStack::new()
84 .spacing(16.0)
85 .alignment(HorizontalAlignment::Leading)
86 .child(Text::new("ZStack overlays children, centered by default:"))
87 .child(
88 ZStack::new()
89 .child(div().size(px(150.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
90 .child(div().size(px(80.0)).bg(rgb(0xFF3B30)).rounded_full())
91 .frame_size(200.0, 200.0)
92 .background(Color::tertiary_system_background())
93 .corner_radius(8.0),
94 )
95}
96
97pub fn render_spacer_story() -> impl IntoElement {
98 VStack::new()
99 .spacing(16.0)
100 .alignment(HorizontalAlignment::Leading)
101 .child(Text::new("Spacer pushes content to edges:"))
102 .child(
103 HStack::new()
104 .child(Text::new("Left").padding(8.0).background(Color::blue()))
105 .child(Spacer::new())
106 .child(Text::new("Right").padding(8.0).background(Color::blue()))
107 .padding(16.0)
108 .background(Color::tertiary_system_background())
109 .corner_radius(8.0)
110 .frame_width(400.0),
111 )
112 .child(Text::new("Multiple spacers distribute evenly:"))
113 .child(
114 HStack::new()
115 .child(Spacer::new())
116 .child(Text::new("Center").padding(8.0).background(Color::green()))
117 .child(Spacer::new())
118 .padding(16.0)
119 .background(Color::tertiary_system_background())
120 .corner_radius(8.0)
121 .frame_width(400.0),
122 )
123}More examples
6pub fn render_scrollview_story() -> impl IntoElement {
7 VStack::new()
8 .spacing(16.0)
9 .alignment(HorizontalAlignment::Leading)
10 .child(Text::new("ScrollView - Scrollable container for content:"))
11 .child(
12 VStack::new()
13 .spacing(16.0)
14 .child(Text::new("Vertical scroll (default):"))
15 .child(
16 ScrollView::new("vertical-scroll")
17 .axes(ScrollAxes::vertical())
18 .child(VStack::new().spacing(8.0).children((1..=20).map(|i| {
19 Text::new(format!("Item {}", i))
20 .padding(12.0)
21 .background(Color::tertiary_system_background())
22 .corner_radius(4.0)
23 })))
24 .frame(Frame::size(300.0, 200.0))
25 .background(Color::tertiary_system_background())
26 .corner_radius(8.0),
27 )
28 .child(Text::new("Horizontal scroll:"))
29 .child(
30 ScrollView::new("horizontal-scroll")
31 .axes(ScrollAxes::horizontal())
32 .child(HStack::new().spacing(8.0).children((1..=15).map(|i| {
33 VStack::new()
34 .child(div().size(px(60.0)).bg(rgb(0x007AFF)).rounded(px(8.0)))
35 .child(Text::new(format!("{}", i)))
36 .spacing(4.0)
37 .padding(8.0)
38 })))
39 .frame(Frame::size(400.0, 120.0))
40 .background(Color::tertiary_system_background())
41 .corner_radius(8.0),
42 ),
43 )
44}
45
46pub fn render_list_story() -> impl IntoElement {
47 VStack::new()
48 .spacing(16.0)
49 .alignment(HorizontalAlignment::Leading)
50 .child(Text::new("List & Section - iOS-style grouped lists:"))
51 .child(
52 HStack::new()
53 .spacing(24.0)
54 .alignment(VerticalAlignment::Top)
55 .child(
56 VStack::new()
57 .spacing(8.0)
58 .child(Text::new("Inset Grouped (Dark):").foreground_color(Color::gray()))
59 .child(
60 List::new("settings-list")
61 .list_style(ListStyle::inset_grouped())
62 .child(
63 Section::new()
64 .header("Account")
65 .child(Text::new("Profile"))
66 .child(Text::new("Privacy"))
67 .child(Text::new("Security")),
68 )
69 .child(
70 Section::new()
71 .header("Preferences")
72 .footer("Customize your experience")
73 .child(Text::new("Notifications"))
74 .child(Text::new("Appearance"))
75 .child(Text::new("Language")),
76 )
77 .frame(Frame::size(280.0, 380.0))
78 .background(Color::system_background())
79 .corner_radius(12.0),
80 ),
81 )
82 .child(
83 VStack::new()
84 .spacing(8.0)
85 .child(Text::new("Plain (Dark):").foreground_color(Color::gray()))
86 .child(
87 List::new("plain-list")
88 .list_style(ListStyle::plain())
89 .child(
90 Section::new()
91 .child(Text::new("First Item"))
92 .child(Text::new("Second Item"))
93 .child(Text::new("Third Item")),
94 )
95 .frame(Frame::size(200.0, 200.0))
96 .background(Color::system_background())
97 .corner_radius(8.0),
98 ),
99 ),
100 )
101}
102
103pub fn render_foreach_story() -> impl IntoElement {
104 let fruits = vec!["Apple", "Banana", "Cherry", "Date", "Elderberry"];
105 let numbers = vec![1, 2, 3, 4, 5];
106
107 VStack::new()
108 .spacing(16.0)
109 .alignment(HorizontalAlignment::Leading)
110 .child(Text::new("ForEach - Iterate over collections:"))
111 .child(
112 HStack::new()
113 .spacing(32.0)
114 .alignment(VerticalAlignment::Top)
115 .child(
116 VStack::new()
117 .spacing(8.0)
118 .child(Text::new("String list:").foreground_color(Color::gray()))
119 .child(
120 VStack::new()
121 .spacing(4.0)
122 .children(ForEach::new(fruits, |fruit| {
123 HStack::new()
124 .spacing(8.0)
125 .child(div().size(px(8.0)).bg(rgb(0x34C759)).rounded_full())
126 .child(Text::new(*fruit))
127 }))
128 .padding(16.0)
129 .background(Color::tertiary_system_background())
130 .corner_radius(8.0),
131 ),
132 )
133 .child(
134 VStack::new()
135 .spacing(8.0)
136 .child(Text::new("Number grid:").foreground_color(Color::gray()))
137 .child(
138 HStack::new()
139 .spacing(8.0)
140 .children(ForEach::new(numbers, |num| {
141 Text::new(format!("{}", num))
142 .padding(16.0)
143 .background(Color::blue())
144 .corner_radius(8.0)
145 }))
146 .padding(16.0)
147 .background(Color::tertiary_system_background())
148 .corner_radius(8.0),
149 ),
150 ),
151 )
152 .child(
153 Text::new("ForEach works with VStack.children(), HStack.children(), etc.")
154 .foreground_color(Color::gray()),
155 )
156}
157
158pub fn render_conditional_story(
159 storybook: &Storybook,
160 cx: &mut Context<Storybook>,
161) -> impl IntoElement {
162 let show_content = storybook.show_content;
163 let selected_fruit = storybook.selected_fruit;
164 let entity = cx.entity().clone();
165 let entity2 = cx.entity().clone();
166
167 let fruits = ["Apple", "Banana", "Cherry"];
168
169 VStack::new()
170 .spacing(16.0)
171 .alignment(HorizontalAlignment::Leading)
172 .child(Text::new("If - Conditional rendering:"))
173 .child(
174 VStack::new()
175 .spacing(12.0)
176 .child(HStack::new().spacing(12.0).child(Toggle::new_with_handler(
177 "Show Content",
178 show_content,
179 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
180 this.show_content = *checked;
181 cx.notify();
182 }),
183 )))
184 .child(
185 If::new(show_content)
186 .then(|| {
187 Text::new("Content is visible!")
188 .padding(16.0)
189 .background(Color::green())
190 .corner_radius(8.0)
191 })
192 .otherwise(|| {
193 Text::new("Content is hidden")
194 .padding(16.0)
195 .background(Color::red())
196 .corner_radius(8.0)
197 }),
198 )
199 .padding(16.0)
200 .background(Color::tertiary_system_background())
201 .corner_radius(8.0),
202 )
203 .child(Text::new("IfLet - Render when Option is Some:"))
204 .child(
205 VStack::new()
206 .spacing(12.0)
207 .child(
208 HStack::new()
209 .spacing(8.0)
210 .children(fruits.iter().enumerate().map(|(idx, fruit)| {
211 let is_selected = selected_fruit == Some(idx);
212 let entity = entity.clone();
213 Text::new(*fruit)
214 .padding(8.0)
215 .background(if is_selected {
216 Color::blue()
217 } else {
218 Color::secondary()
219 })
220 .corner_radius(4.0)
221 .on_tap_gesture_with(
222 SharedString::from(format!("fruit-{}", idx)),
223 move |_, _, cx| {
224 entity.update(cx, |this, cx| {
225 this.selected_fruit = Some(idx);
226 cx.notify();
227 });
228 },
229 )
230 }))
231 .child(
232 Text::new("None")
233 .padding(8.0)
234 .background(if selected_fruit.is_none() {
235 Color::blue()
236 } else {
237 Color::secondary()
238 })
239 .corner_radius(4.0)
240 .on_tap_gesture_with("fruit-none", move |_, _, cx| {
241 entity2.update(cx, |this, cx| {
242 this.selected_fruit = None;
243 cx.notify();
244 });
245 }),
246 ),
247 )
248 .child(IfLet::new(selected_fruit, move |idx| {
249 let fruit_names = ["Apple", "Banana", "Cherry"];
250 Text::new(format!("Selected: {} (index {})", fruit_names[*idx], idx))
251 .padding(12.0)
252 .background(Color::green())
253 .corner_radius(8.0)
254 }))
255 .child(
256 If::new(selected_fruit.is_none())
257 .then(|| {
258 Text::new("No fruit selected")
259 .padding(12.0)
260 .foreground_color(Color::gray())
261 })
262 .otherwise(EmptyView::new),
263 )
264 .padding(16.0)
265 .background(Color::tertiary_system_background())
266 .corner_radius(8.0),
267 )
268}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}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}Sourcefn shadow_with(
self,
radius: f32,
color: impl Into<Color>,
x: f32,
y: f32,
) -> Modified<Self>
fn shadow_with( self, radius: f32, color: impl Into<Color>, x: f32, y: f32, ) -> Modified<Self>
Add a shadow with full configuration.
Hide the view.
Sourcefn on_tap_gesture(
self,
id: impl Into<SharedString>,
handler: impl Fn() + 'static,
) -> Tappable<Self>
fn on_tap_gesture( self, id: impl Into<SharedString>, handler: impl Fn() + 'static, ) -> Tappable<Self>
Sourcefn on_tap_gesture_with(
self,
id: impl Into<SharedString>,
handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
) -> Tappable<Self>
fn on_tap_gesture_with( self, id: impl Into<SharedString>, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, ) -> Tappable<Self>
Add a tap gesture handler with access to the event.
Examples found in repository?
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}More examples
158pub fn render_conditional_story(
159 storybook: &Storybook,
160 cx: &mut Context<Storybook>,
161) -> impl IntoElement {
162 let show_content = storybook.show_content;
163 let selected_fruit = storybook.selected_fruit;
164 let entity = cx.entity().clone();
165 let entity2 = cx.entity().clone();
166
167 let fruits = ["Apple", "Banana", "Cherry"];
168
169 VStack::new()
170 .spacing(16.0)
171 .alignment(HorizontalAlignment::Leading)
172 .child(Text::new("If - Conditional rendering:"))
173 .child(
174 VStack::new()
175 .spacing(12.0)
176 .child(HStack::new().spacing(12.0).child(Toggle::new_with_handler(
177 "Show Content",
178 show_content,
179 cx.listener(|this: &mut Storybook, checked: &bool, _window, cx| {
180 this.show_content = *checked;
181 cx.notify();
182 }),
183 )))
184 .child(
185 If::new(show_content)
186 .then(|| {
187 Text::new("Content is visible!")
188 .padding(16.0)
189 .background(Color::green())
190 .corner_radius(8.0)
191 })
192 .otherwise(|| {
193 Text::new("Content is hidden")
194 .padding(16.0)
195 .background(Color::red())
196 .corner_radius(8.0)
197 }),
198 )
199 .padding(16.0)
200 .background(Color::tertiary_system_background())
201 .corner_radius(8.0),
202 )
203 .child(Text::new("IfLet - Render when Option is Some:"))
204 .child(
205 VStack::new()
206 .spacing(12.0)
207 .child(
208 HStack::new()
209 .spacing(8.0)
210 .children(fruits.iter().enumerate().map(|(idx, fruit)| {
211 let is_selected = selected_fruit == Some(idx);
212 let entity = entity.clone();
213 Text::new(*fruit)
214 .padding(8.0)
215 .background(if is_selected {
216 Color::blue()
217 } else {
218 Color::secondary()
219 })
220 .corner_radius(4.0)
221 .on_tap_gesture_with(
222 SharedString::from(format!("fruit-{}", idx)),
223 move |_, _, cx| {
224 entity.update(cx, |this, cx| {
225 this.selected_fruit = Some(idx);
226 cx.notify();
227 });
228 },
229 )
230 }))
231 .child(
232 Text::new("None")
233 .padding(8.0)
234 .background(if selected_fruit.is_none() {
235 Color::blue()
236 } else {
237 Color::secondary()
238 })
239 .corner_radius(4.0)
240 .on_tap_gesture_with("fruit-none", move |_, _, cx| {
241 entity2.update(cx, |this, cx| {
242 this.selected_fruit = None;
243 cx.notify();
244 });
245 }),
246 ),
247 )
248 .child(IfLet::new(selected_fruit, move |idx| {
249 let fruit_names = ["Apple", "Banana", "Cherry"];
250 Text::new(format!("Selected: {} (index {})", fruit_names[*idx], idx))
251 .padding(12.0)
252 .background(Color::green())
253 .corner_radius(8.0)
254 }))
255 .child(
256 If::new(selected_fruit.is_none())
257 .then(|| {
258 Text::new("No fruit selected")
259 .padding(12.0)
260 .foreground_color(Color::gray())
261 })
262 .otherwise(EmptyView::new),
263 )
264 .padding(16.0)
265 .background(Color::tertiary_system_background())
266 .corner_radius(8.0),
267 )
268}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.