08_system_monitor/
08_system_monitor.rs1use crossterm::event::KeyCode;
8use crossterm::style::Color;
9use std::time::Duration;
10use telex::prelude::*;
11
12telex::require_api!(0, 2);
13
14fn main() {
15 telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
16}
17
18struct App;
19
20impl Component for App {
21 fn render(&self, cx: Scope) -> View {
22 let show_help = state!(cx, || false);
23
24 cx.use_command(
26 KeyBinding::key(KeyCode::F(1)),
27 with!(show_help => move || show_help.update(|v| *v = !*v)),
28 );
29
30 let cpu = stream!(cx, || {
32 let mut rng_state = 42u64;
33 (0..).map(move |_| {
34 std::thread::sleep(Duration::from_millis(500));
35 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
37
38 ((rng_state >> 16) % 80) as u8 + 10
39 })
40 });
41
42 let memory = stream!(cx, || {
44 (0..).map(|i| {
45 std::thread::sleep(Duration::from_millis(800));
46 let cycle = i % 20;
47 if cycle < 15 {
48 40 + (cycle * 3) as u8
49 } else {
50 40 + ((20 - cycle) * 8) as u8
51 }
52 })
53 });
54
55 let network = stream!(cx, || {
57 let mut rng_state = 123u64;
58 (0..).map(move |_| {
59 std::thread::sleep(Duration::from_millis(300));
60 rng_state = rng_state.wrapping_mul(1103515245).wrapping_add(12345);
61
62 ((rng_state >> 16) % 1000) as u32 + 100
63 })
64 });
65
66 let cpu_val = cpu.get();
67 let mem_val = memory.get();
68 let net_val = network.get();
69
70 let cpu_color = if cpu_val > 80 {
72 Color::Red
73 } else if cpu_val > 50 {
74 Color::Yellow
75 } else {
76 Color::Green
77 };
78
79 let mem_color = if mem_val > 80 {
80 Color::Red
81 } else if mem_val > 60 {
82 Color::Yellow
83 } else {
84 Color::Green
85 };
86
87 fn progress_bar(value: u8, width: usize) -> String {
89 let filled = (value as usize * width) / 100;
90 let empty = width - filled;
91 format!("[{}{}]", "#".repeat(filled), "-".repeat(empty))
92 }
93
94 View::vstack()
95 .child(
96 View::styled_text("System Monitor")
97 .color(Color::Cyan)
98 .bold()
99 .build(),
100 )
101 .child(View::gap(1))
102 .child(
103 View::hstack()
104 .child(View::text("CPU: "))
105 .child(
106 View::styled_text(progress_bar(cpu_val, 20))
107 .color(cpu_color)
108 .build(),
109 )
110 .child(
111 View::styled_text(format!(" {:>3}%", cpu_val))
112 .bold()
113 .build(),
114 )
115 .build(),
116 )
117 .child(
118 View::hstack()
119 .child(View::text("Memory: "))
120 .child(
121 View::styled_text(progress_bar(mem_val, 20))
122 .color(mem_color)
123 .build(),
124 )
125 .child(
126 View::styled_text(format!(" {:>3}%", mem_val))
127 .bold()
128 .build(),
129 )
130 .build(),
131 )
132 .child(View::gap(1))
133 .child(
134 View::hstack()
135 .child(View::text("Network: "))
136 .child(
137 View::styled_text(format!("{:>6} KB/s", net_val))
138 .color(Color::Magenta)
139 .build(),
140 )
141 .build(),
142 )
143 .child(View::gap(1))
144 .child(View::styled_text("F1 help • Ctrl+Q quit").dim().build())
145 .child(
146 View::modal()
147 .visible(show_help.get())
148 .title("Example 08: System Monitor")
149 .on_dismiss(with!(show_help => move || show_help.set(false)))
150 .child(
151 View::vstack()
152 .child(View::styled_text("What you're seeing").bold().build())
153 .child(View::text(
154 "• Multiple independent streams running together",
155 ))
156 .child(View::text("• Color-coded thresholds (green/yellow/red)"))
157 .child(View::text("• ASCII progress bars"))
158 .child(View::gap(1))
159 .child(View::styled_text("Key concepts").bold().build())
160 .child(View::text("• Each stream!() runs in its own thread"))
161 .child(View::text(
162 "• Streams update independently at different rates",
163 ))
164 .child(View::text("• Conditional styling based on values"))
165 .child(View::gap(1))
166 .child(View::styled_text("Try this").bold().build())
167 .child(View::text("• Watch CPU fluctuate randomly"))
168 .child(View::text("• Memory climbs then drops cyclically"))
169 .child(View::text("• Network updates fastest (300ms)"))
170 .child(View::gap(1))
171 .child(View::styled_text("Next up").bold().build())
172 .child(View::text(
173 "→ 09_syntax_comparison: builder vs macro syntax",
174 ))
175 .child(View::gap(1))
176 .child(View::styled_text("Press Escape to close").dim().build())
177 .build(),
178 )
179 .build(),
180 )
181 .build()
182 }
183}