1use sparcli::prelude::*;
8use sparcli::{
9 Badge, Cell, Column, Columns, KeyValue, List, Marker, Panel, ProgressBar,
10 Rule, Table, Tree, TreeNode,
11};
12
13fn main() -> Result<()> {
14 println!();
15 hero()?;
16 println!();
17 dashboard()?;
18 println!();
19 progress()?;
20 Ok(())
21}
22
23fn blank() -> Rendered {
25 Rendered::new(vec![Line::default()])
26}
27
28fn hero() -> Result<()> {
30 let cyan = Style::new().fg(Color::Cyan).bold();
31 let on_magenta = Style::new().fg(Color::Black).bg(Color::Magenta).bold();
32 let yellow = Style::new().fg(Color::Yellow).bold();
33 let body = Text::new(vec![
34 Line::new(vec![
35 Span::raw("A native Rust library for "),
36 Span::styled("styled terminal output", cyan),
37 Span::raw(" and "),
38 Span::styled("input", on_magenta),
39 Span::raw(" - panels, tables, trees, lists,"),
40 ]),
41 Line::new(vec![
42 Span::raw("key-value pairs, badges, rules, "),
43 Span::styled("columns", cyan),
44 Span::raw(" and progress bars, with Rich-compatible "),
45 Span::styled("[markup]", yellow),
46 Span::raw("."),
47 ]),
48 ]);
49 Panel::new(body)
50 .border(BorderType::Rounded)
51 .border_style(Style::new().fg(Color::Cyan))
52 .title(
53 Title::new(" sparcli ")
54 .align(Align::Center)
55 .style(Style::new().fg(Color::Cyan).bold()),
56 )
57 .content_align(Align::Center)
58 .width(96)
59 .print()
60}
61
62fn dashboard() -> Result<()> {
64 Columns::new()
65 .add_rendered(overview_table())
66 .add_rendered(middle_column())
67 .add_rendered(right_column())
68 .gap(3)
69 .separator(BorderType::Single)
70 .print()
71}
72
73fn overview_table() -> Rendered {
75 let status = |text: &str, color: Color| {
76 Cell::new(Text::styled(text, Style::new().fg(color).bold()))
77 };
78 Table::new()
79 .title("Overview")
80 .title_style(Style::new().fg(Color::Magenta).bold())
81 .border(BorderType::Rounded)
82 .border_style(Style::new().fg(Color::Magenta))
83 .header_style(Style::new().fg(Color::Cyan).bold())
84 .striped(true)
85 .stripe_style(Style::new().bg(Color::Rgb(40, 40, 60)))
86 .row_separators(true)
87 .columns([
88 Column::new("Service"),
89 Column::new("Status").align(Align::Center),
90 Column::new("Uptime").align(Align::Right),
91 ])
92 .row([
93 Cell::new("api-gateway"),
94 status("● OK", Color::Green),
95 Cell::new("99.98%"),
96 ])
97 .row([
98 Cell::new("auth"),
99 status("● OK", Color::Green),
100 Cell::new("99.91%"),
101 ])
102 .row([
103 Cell::new("billing"),
104 status("● WARN", Color::Yellow),
105 Cell::new("97.40%"),
106 ])
107 .row([
108 Cell::new("scheduler"),
109 status("● FAIL", Color::Red),
110 Cell::new("82.10%"),
111 ])
112 .render(40)
113}
114
115fn middle_column() -> Rendered {
117 let list = List::ordered(Marker::Number)
118 .marker_style(Style::new().fg(Color::Yellow).bold())
119 .item("Compose widgets side by side")
120 .item("Capture, pad, and align them")
121 .item("Style with Rich-style markup")
122 .item("Render to any UTF-8 terminal")
123 .render(36);
124
125 let tree = Tree::new()
126 .dashes(2)
127 .connector_style(Style::new().fg(Color::Cyan))
128 .node(
129 TreeNode::new("project/")
130 .child(
131 TreeNode::new("api/")
132 .child(TreeNode::new("routes.c"))
133 .child(TreeNode::new("auth.c")),
134 )
135 .child(TreeNode::new("worker.c"))
136 .child(TreeNode::new("store.c")),
137 )
138 .render(18);
139
140 let rules = vstack(
141 &[
142 rule("Pipeline", BorderType::Single, Color::Magenta),
143 blank(),
144 rule("Workers", BorderType::Double, Color::Green),
145 blank(),
146 rule("Storage", BorderType::Thick, Color::Yellow),
147 blank(),
148 ],
149 0,
150 );
151
152 let tree_and_rules = Columns::new()
153 .add_rendered(tree)
154 .add_rendered(rules)
155 .gap(2)
156 .render(40);
157
158 vstack(&[list, blank(), tree_and_rules], 0)
159}
160
161fn rule(title: &str, border: BorderType, color: Color) -> Rendered {
163 Rule::with_title(Text::styled(title, Style::new().fg(color).bold()))
164 .border(border)
165 .style(Style::new().fg(color))
166 .width(20)
167 .render(20)
168}
169
170fn right_column() -> Rendered {
172 let kv = KeyValue::new()
173 .key_style(Style::new().fg(Color::Cyan).bold())
174 .value_style(Style::new())
175 .add("host", "localhost")
176 .add("port", "8080")
177 .add("scheme", "https")
178 .add("timeout", "30s")
179 .render(24);
180
181 let badge = |text: &str, color: Color| {
182 Badge::new(text)
183 .pad(1)
184 .style(Style::new().fg(Color::Black).bg(color).bold())
185 .span()
186 };
187 let badges = Rendered::new(vec![
188 Line::new(vec![
189 badge("DONE", Color::Green),
190 Span::raw(" "),
191 badge("INFO", Color::LightBlue),
192 ]),
193 Line::default(),
194 Line::new(vec![
195 badge("WARN", Color::Yellow),
196 Span::raw(" "),
197 badge("FAIL", Color::Red),
198 ]),
199 ]);
200
201 let label = |text: &str| {
202 Rendered::new(vec![Line::styled(
203 text,
204 Style::new().fg(Color::Cyan).bold(),
205 )])
206 };
207 let staggered = Columns::new()
208 .add_rendered(label("Col 1"))
209 .add_rendered(vstack(&[blank(), label("Col 2")], 0))
210 .add_rendered(vstack(&[blank(), blank(), label("Col 3")], 0))
211 .gap(2)
212 .separator(BorderType::Single)
213 .render(40);
214
215 vstack(&[kv, blank(), badges, blank(), staggered], 0)
216}
217
218fn progress() -> Result<()> {
220 ProgressBar::new()
221 .label("Building")
222 .fill_color(Color::Green)
223 .caps("[", "]")
224 .width(29)
225 .show_value(true)
226 .bar(92.0, 100.0)
227 .print()
228}