13_split_panes/
13_split_panes.rs1use crossterm::event::KeyCode;
8use crossterm::style::Color;
9use telex::prelude::*;
10
11telex::require_api!(0, 2);
12
13fn main() {
14 telex::run_with_theme(App, telex::theme::Theme::nord()).unwrap();
15}
16
17struct App;
18
19impl Component for App {
20 fn render(&self, cx: Scope) -> View {
21 let show_help = state!(cx, || false);
22
23 cx.use_command(
25 KeyBinding::key(KeyCode::F(1)),
26 with!(show_help => move || show_help.update(|v| *v = !*v)),
27 );
28
29 let selected_item = state!(cx, || 0usize);
30
31 let items = vec![
32 "README.md".to_string(),
33 "Cargo.toml".to_string(),
34 "src/".to_string(),
35 "src/main.rs".to_string(),
36 "src/lib.rs".to_string(),
37 "tests/".to_string(),
38 ];
39
40 let on_select = with!(selected_item => move |idx: usize| {
41 selected_item.set(idx);
42 });
43
44 let detail_text = match selected_item.get() {
45 0 => "# README\n\nThis is a demo of split panes.\n\nThe left panel shows a file list,\nthe right panel shows details.",
46 1 => "[package]\nname = \"demo\"\nversion = \"0.1.0\"\nedition = \"2021\"",
47 2 => "Directory: src/\n\nContains the main source files.",
48 3 => "fn main() {\n println!(\"Hello, world!\");\n}",
49 4 => "pub mod utils;\npub mod widgets;",
50 5 => "Directory: tests/\n\nContains integration tests.",
51 _ => "Select an item to see details.",
52 };
53
54 View::vstack()
56 .child(
57 View::boxed()
58 .flex(1)
59 .child(
60 View::split()
61 .horizontal()
62 .ratio(0.3)
63 .min_first(15)
64 .first(
65 View::vstack()
66 .child(
67 View::styled_text("Files")
68 .color(Color::Cyan)
69 .bold()
70 .build(),
71 )
72 .child(
73 View::list()
74 .items(items)
75 .selected(selected_item.get())
76 .on_select(on_select)
77 .build(),
78 )
79 .child(View::gap(1))
80 .build(),
81 )
82 .second(
83 View::vstack()
84 .child(
85 View::styled_text("Details")
86 .color(Color::Green)
87 .bold()
88 .build(),
89 )
90 .child(
91 View::boxed()
92 .border(true)
93 .flex(1)
94 .child(View::text(detail_text))
95 .build(),
96 )
97 .build(),
98 )
99 .build(),
100 )
101 .build(),
102 )
103 .child(
104 View::styled_text("↑↓: select file | F1 help | Ctrl+Q: quit")
105 .dim()
106 .build(),
107 )
108 .child(
109 View::modal()
110 .visible(show_help.get())
111 .title("Example 13: Split Panes")
112 .on_dismiss(with!(show_help => move || show_help.set(false)))
113 .child(
114 View::vstack()
115 .child(View::styled_text("What you're seeing").bold().build())
116 .child(View::text("• Horizontal split: file list / details"))
117 .child(View::text("• ratio(0.3) = 30% left, 70% right"))
118 .child(View::text("• min_first(15) sets minimum pane width"))
119 .child(View::gap(1))
120 .child(View::styled_text("Key concepts").bold().build())
121 .child(View::text("• View::split() creates resizable panes"))
122 .child(View::text("• .horizontal() or .vertical() orientation"))
123 .child(View::text("• .first() and .second() set pane content"))
124 .child(View::text("• Splits can be nested"))
125 .child(View::gap(1))
126 .child(View::styled_text("Try this").bold().build())
127 .child(View::text("• Select different files to see details"))
128 .child(View::text("• Resize terminal to see layout adapt"))
129 .child(View::gap(1))
130 .child(View::styled_text("Next up").bold().build())
131 .child(View::text("→ 14_tabs: tabbed interfaces"))
132 .child(View::gap(1))
133 .child(View::styled_text("Press Escape to close").dim().build())
134 .build(),
135 )
136 .build(),
137 )
138 .build()
139 }
140}