09_syntax_comparison/
09_syntax_comparison.rs1use crossterm::event::KeyCode;
12use telex::prelude::*;
13use telex::Color;
14
15telex::require_api!(0, 2);
16
17fn main() {
18 telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
19}
20
21struct App;
22
23impl Component for App {
24 fn render(&self, cx: Scope) -> View {
25 let use_jsx = state!(cx, || false);
26 let show_help = state!(cx, || false);
27
28 cx.use_command(
30 KeyBinding::key(KeyCode::F(1)),
31 with!(show_help => move || show_help.update(|v| *v = !*v)),
32 );
33
34 let toggle = with!(use_jsx => move || use_jsx.set(!use_jsx.get()));
35
36 let syntax_name = if use_jsx.get() {
38 "view! macro (JSX-like)"
39 } else {
40 "Builder pattern"
41 };
42
43 View::vstack()
44 .child(
45 View::styled_text("Syntax Comparison")
46 .color(Color::Cyan)
47 .bold()
48 .build(),
49 )
50 .child(
51 View::styled_text("Same UI, two ways to write it")
52 .dim()
53 .build(),
54 )
55 .child(View::gap(1))
56 .child(
57 View::hstack()
58 .child(View::text("Current syntax: "))
59 .child(
60 View::styled_text(syntax_name)
61 .color(Color::Yellow)
62 .bold()
63 .build(),
64 )
65 .build(),
66 )
67 .child(View::gap(1))
68 .child(
69 View::boxed()
70 .border(true)
71 .padding(1)
72 .child(if use_jsx.get() {
73 counter_jsx(cx.clone())
74 } else {
75 counter_builder(cx.clone())
76 })
77 .build(),
78 )
79 .child(View::gap(1))
80 .child(
81 View::button()
82 .label("Toggle Syntax")
83 .on_press(toggle)
84 .build(),
85 )
86 .child(View::gap(1))
87 .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
88 .child(
89 View::modal()
90 .visible(show_help.get())
91 .title("Example 09: Syntax Comparison")
92 .on_dismiss(with!(show_help => move || show_help.set(false)))
93 .child(
94 View::vstack()
95 .child(View::styled_text("What you're seeing").bold().build())
96 .child(View::text("• Two syntaxes that produce identical output"))
97 .child(View::text("• Builder: View::vstack().child(...).build()"))
98 .child(View::text("• Macro: view! { <VStack>...</VStack> }"))
99 .child(View::gap(1))
100 .child(View::styled_text("Key concepts").bold().build())
101 .child(View::text("• Builder is Rust-native, IDE-friendly"))
102 .child(View::text("• view! macro is JSX-like, less boilerplate"))
103 .child(View::text("• Choose based on your preference"))
104 .child(View::gap(1))
105 .child(View::styled_text("Try this").bold().build())
106 .child(View::text("• Toggle between syntaxes"))
107 .child(View::text("• Notice the output is identical"))
108 .child(View::text("• Check the source code to see both styles"))
109 .child(View::gap(1))
110 .child(View::styled_text("Next up").bold().build())
111 .child(View::text("→ 10_state_explained: deep dive into state"))
112 .child(View::gap(1))
113 .child(View::styled_text("Press Escape to close").dim().build())
114 .build(),
115 )
116 .build(),
117 )
118 .build()
119 }
120}
121
122fn counter_builder(cx: Scope) -> View {
129 let count = state!(cx, || 0i32);
130
131 let increment = with!(count => move || count.update(|n| *n += 1));
133 let decrement = with!(count => move || count.update(|n| *n -= 1));
134
135 View::vstack()
136 .child(
137 View::styled_text("// Built with builder pattern")
138 .color(Color::DarkGrey)
139 .build(),
140 )
141 .child(View::gap(1))
142 .child(
143 View::styled_text(format!("Count: {}", count.get()))
144 .bold()
145 .build(),
146 )
147 .child(View::gap(1))
148 .child(
149 View::hstack()
150 .child(View::button().label(" - ").on_press(decrement).build())
151 .child(View::text(" "))
152 .child(View::button().label(" + ").on_press(increment).build())
153 .build(),
154 )
155 .build()
156}
157
158fn counter_jsx(cx: Scope) -> View {
165 let count = state!(cx, || 0i32);
166
167 view! {
169 <VStack>
170 <StyledText color={Color::DarkGrey}>"// Built with view! macro + with!"</StyledText>
171 <Spacer />
172 <StyledText bold={true}>{format!("Count: {}", count.get())}</StyledText>
173 <Spacer />
174 <HStack>
175 <Button on_press={with!(count => move || count.update(|n| *n -= 1))}>" - "</Button>
176 <Text>" "</Text>
177 <Button on_press={with!(count => move || count.update(|n| *n += 1))}>" + "</Button>
178 </HStack>
179 </VStack>
180 }
181}