28_shared_state/
28_shared_state.rs1use crossterm::event::KeyCode;
14use telex::prelude::*;
15use telex::Color;
16
17telex::require_api!(0, 2);
18
19struct SharedCounterKey;
21
22fn main() {
23 telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
24}
25
26struct App;
27
28impl Component for App {
29 fn render(&self, cx: Scope) -> View {
30 let show_help = state!(cx, || false);
31
32 cx.use_command(
34 KeyBinding::key(KeyCode::F(1)),
35 with!(show_help => move || show_help.update(|v| *v = !*v)),
36 );
37
38 let count_a = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);
43 let inc_a = with!(count_a => move || count_a.update(|n| *n += 1));
44
45 let count_b = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);
47 let inc_b = with!(count_b => move || count_b.update(|n| *n += 1));
48
49 View::vstack()
50 .spacing(1)
51 .child(
52 View::styled_text("Shared State Demo")
53 .color(Color::Cyan)
54 .bold()
55 .build(),
56 )
57 .child(View::gap(1))
58 .child(
59 View::hstack()
60 .spacing(2)
61 .child(
63 View::boxed()
64 .border(true)
65 .padding(1)
66 .max_width(25)
67 .child(
68 View::vstack()
69 .child(View::styled_text("Pane A").bold().build())
70 .child(View::gap(1))
71 .child(
72 View::hstack()
73 .spacing(1)
74 .child(View::text("Value:"))
75 .child(
76 View::styled_text(format!("{}", count_a.get()))
77 .color(Color::Yellow)
78 .bold()
79 .build(),
80 )
81 .child(View::button().label("+").on_press(inc_a).build())
82 .build(),
83 )
84 .build(),
85 )
86 .build(),
87 )
88 .child(
90 View::boxed()
91 .border(true)
92 .padding(1)
93 .max_width(25)
94 .child(
95 View::vstack()
96 .child(View::styled_text("Pane B").bold().build())
97 .child(View::gap(1))
98 .child(
99 View::hstack()
100 .spacing(1)
101 .child(View::text("Value:"))
102 .child(
103 View::styled_text(format!("{}", count_b.get()))
104 .color(Color::Yellow)
105 .bold()
106 .build(),
107 )
108 .child(View::button().label("+").on_press(inc_b).build())
109 .build(),
110 )
111 .build(),
112 )
113 .build(),
114 )
115 .build(),
116 )
117 .child(View::gap(1))
118 .child(View::styled_text("Try this:").bold().build())
119 .child(View::text(" 1. Click + on Pane A"))
120 .child(View::text(" 2. Watch Pane B update too!"))
121 .child(View::text(" 3. Click + on Pane B - same thing"))
122 .child(View::gap(1))
123 .child(
124 View::styled_text("Both panes share the SAME state.")
125 .color(Color::Green)
126 .build(),
127 )
128 .child(View::gap(1))
129 .child(
130 View::boxed()
131 .border(true)
132 .padding(1)
133 .child(
134 View::vstack()
135 .child(View::styled_text("The code:").bold().build())
136 .child(View::gap(1))
137 .child(
138 View::styled_text("struct SharedCounterKey; // Named key type")
139 .color(Color::Green)
140 .build(),
141 )
142 .child(View::gap(1))
143 .child(View::styled_text("// Pane A").color(Color::DarkGrey).build())
144 .child(
145 View::styled_text("let count_a = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);")
146 .color(Color::Yellow)
147 .build(),
148 )
149 .child(View::gap(1))
150 .child(View::styled_text("// Pane B - SAME key type!").color(Color::DarkGrey).build())
151 .child(
152 View::styled_text("let count_b = cx.use_state_keyed::<SharedCounterKey, _>(|| 0);")
153 .color(Color::Yellow)
154 .build(),
155 )
156 .child(View::gap(1))
157 .child(View::text("Same key = same state. Both variables"))
158 .child(View::text("point to the same underlying value."))
159 .build(),
160 )
161 .build(),
162 )
163 .child(View::gap(1))
164 .child(
165 View::boxed()
166 .border(true)
167 .padding(1)
168 .child(
169 View::vstack()
170 .child(View::styled_text("Compare with example 27:").bold().build())
171 .child(View::gap(1))
172 .child(View::styled_text("state!(cx, || 0) // Anonymous key").color(Color::Magenta).build())
173 .child(View::text(" Each call = unique key = independent state"))
174 .child(View::gap(1))
175 .child(View::styled_text("cx.use_state_keyed::<MyKey, _>(|| 0) // Named key").color(Color::Yellow).build())
176 .child(View::text(" Same key = same state = shared everywhere"))
177 .build(),
178 )
179 .build(),
180 )
181 .child(View::gap(1))
182 .child(View::styled_text("Tab: navigate | F1 help | Ctrl+Q: quit").dim().build())
183 .child(
184 View::modal()
185 .visible(show_help.get())
186 .title("Example 28: Shared State")
187 .on_dismiss(with!(show_help => move || show_help.set(false)))
188 .child(
189 View::vstack()
190 .child(View::styled_text("What you're seeing").bold().build())
191 .child(View::text("• Two panes sharing ONE counter"))
192 .child(View::text("• Both + buttons increment same value"))
193 .child(View::text("• Named key type = shared state"))
194 .child(View::gap(1))
195 .child(View::styled_text("Key concepts").bold().build())
196 .child(View::text("• struct SharedCounterKey; defines key"))
197 .child(View::text("• use_state_keyed::<Key, _>() uses it"))
198 .child(View::text("• Same key = same underlying value"))
199 .child(View::text("• Opposite of state! (unique keys)"))
200 .child(View::gap(1))
201 .child(View::styled_text("Try this").bold().build())
202 .child(View::text("• Click + on Pane A"))
203 .child(View::text("• Watch Pane B update too!"))
204 .child(View::text("• Both buttons modify same state"))
205 .child(View::gap(1))
206 .child(View::styled_text("Next up").bold().build())
207 .child(View::text("→ 29_canvas: pixel graphics"))
208 .child(View::gap(1))
209 .child(View::styled_text("Press Escape to close").dim().build())
210 .build()
211 )
212 .build()
213 )
214 .build()
215 }
216}