1use crossterm::event::KeyCode;
9use std::time::Duration;
10use telex::prelude::*;
11use telex::Color;
12
13telex::require_api!(0, 2);
14
15fn main() {
16 telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
17}
18
19struct App;
20
21impl Component for App {
22 fn render(&self, cx: Scope) -> View {
23 let show_help = state!(cx, || false);
24
25 cx.use_command(
27 KeyBinding::key(KeyCode::F(1)),
28 with!(show_help => move || show_help.update(|v| *v = !*v)),
29 );
30
31 let toasts = state!(cx, || ToastQueue::with_duration(Duration::from_secs(3)));
33 let position = state!(cx, || ToastPosition::BottomRight);
34
35 let show_info = with!(toasts => move || {
37 toasts.get().info("This is an informational message");
38 });
39
40 let show_success = with!(toasts => move || {
41 toasts.get().success("Operation completed successfully!");
42 });
43
44 let show_warning = with!(toasts => move || {
45 toasts.get().warning("Warning: This action cannot be undone");
46 });
47
48 let show_error = with!(toasts => move || {
49 toasts.get().error("Error: Connection failed");
50 });
51
52 let show_long_error = with!(toasts => move || {
53 toasts.get().error_long("Critical Error: Server not responding. Check your network.");
54 });
55
56 let clear_all = with!(toasts => move || {
57 toasts.get().clear();
58 });
59
60 let cycle_position = with!(position => move || {
62 let next = match position.get() {
63 ToastPosition::TopRight => ToastPosition::TopLeft,
64 ToastPosition::TopLeft => ToastPosition::BottomLeft,
65 ToastPosition::BottomLeft => ToastPosition::BottomRight,
66 ToastPosition::BottomRight => ToastPosition::TopRight,
67 };
68 position.set(next);
69 });
70
71 let position_name = match position.get() {
72 ToastPosition::TopRight => "Top Right",
73 ToastPosition::TopLeft => "Top Left",
74 ToastPosition::BottomLeft => "Bottom Left",
75 ToastPosition::BottomRight => "Bottom Right",
76 };
77
78 View::vstack()
79 .spacing(1)
80 .child(
81 View::boxed()
83 .border(true)
84 .padding(1)
85 .child(
86 View::vstack()
87 .child(View::styled_text("Toast Notifications Demo").bold().build())
88 .child(
89 View::styled_text("Click buttons to show different toast types")
90 .dim()
91 .build(),
92 )
93 .build(),
94 )
95 .build(),
96 )
97 .child(
98 View::boxed()
100 .flex(1)
101 .border(true)
102 .padding(1)
103 .child(
104 View::vstack()
105 .spacing(1)
106 .child(View::text("Toast Types:"))
107 .child(
108 View::hstack()
109 .spacing(2)
110 .child(View::button().label("Info").on_press(show_info).build())
111 .child(
112 View::button()
113 .label("Success")
114 .on_press(show_success)
115 .build(),
116 )
117 .child(
118 View::button()
119 .label("Warning")
120 .on_press(show_warning)
121 .build(),
122 )
123 .child(
124 View::button().label("Error").on_press(show_error).build(),
125 )
126 .build(),
127 )
128 .child(View::gap(1))
129 .child(View::text("Other Actions:"))
130 .child(
131 View::hstack()
132 .spacing(2)
133 .child(
134 View::button()
135 .label("Long Error")
136 .on_press(show_long_error)
137 .build(),
138 )
139 .child(
140 View::button()
141 .label("Clear All")
142 .on_press(clear_all)
143 .build(),
144 )
145 .build(),
146 )
147 .child(View::gap(1))
148 .child(View::text(format!("Position: {}", position_name)))
149 .child(
150 View::button()
151 .label("Change Position")
152 .on_press(cycle_position)
153 .build(),
154 )
155 .child(View::spacer())
156 .child(
157 View::styled_text(format!("Active toasts: {}", toasts.get().len()))
158 .color(Color::Yellow)
159 .build(),
160 )
161 .child(
162 View::styled_text("Toasts auto-dismiss after 3 seconds")
163 .dim()
164 .build(),
165 )
166 .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
167 .build(),
168 )
169 .build(),
170 )
171 .child(
172 View::toast_container()
174 .from_queue(&toasts.get())
175 .position(position.get())
176 .max_visible(5)
177 .width(40)
178 .build(),
179 )
180 .child(
181 View::modal()
182 .visible(show_help.get())
183 .title("Example 21: Toasts")
184 .on_dismiss(with!(show_help => move || show_help.set(false)))
185 .child(
186 View::vstack()
187 .child(View::styled_text("What you're seeing").bold().build())
188 .child(View::text("• Toast notifications in corner"))
189 .child(View::text("• Auto-dismiss after 3 seconds"))
190 .child(View::text(
191 "• Multiple toast types (info/success/warn/error)",
192 ))
193 .child(View::gap(1))
194 .child(View::styled_text("Key concepts").bold().build())
195 .child(View::text("• ToastQueue manages notifications"))
196 .child(View::text("• View::toast_container() renders them"))
197 .child(View::text("• .position() controls corner placement"))
198 .child(View::text("• .max_visible() limits shown toasts"))
199 .child(View::gap(1))
200 .child(View::styled_text("Try this").bold().build())
201 .child(View::text("• Click different toast type buttons"))
202 .child(View::text("• Change position to see toasts move"))
203 .child(View::text("• Spam buttons to stack toasts"))
204 .child(View::gap(1))
205 .child(View::styled_text("Next up").bold().build())
206 .child(View::text("→ 22_forms: form validation"))
207 .child(View::gap(1))
208 .child(View::styled_text("Press Escape to close").dim().build())
209 .build(),
210 )
211 .build(),
212 )
213 .build()
214 }
215}