use sparcli::prelude::*;
use sparcli::{
Badge, Cell, Column, Columns, KeyValue, List, Marker, Panel, ProgressBar,
Rule, Table, Tree, TreeNode,
};
fn main() -> Result<()> {
println!();
hero()?;
println!();
dashboard()?;
println!();
progress()?;
Ok(())
}
fn blank() -> Rendered {
Rendered::new(vec![Line::default()])
}
fn hero() -> Result<()> {
let cyan = Style::new().fg(Color::Cyan).bold();
let on_magenta = Style::new().fg(Color::Black).bg(Color::Magenta).bold();
let yellow = Style::new().fg(Color::Yellow).bold();
let body = Text::new(vec![
Line::new(vec![
Span::raw("A native Rust library for "),
Span::styled("styled terminal output", cyan),
Span::raw(" and "),
Span::styled("input", on_magenta),
Span::raw(" — panels, tables, trees, lists,"),
]),
Line::new(vec![
Span::raw("key-value pairs, badges, rules, "),
Span::styled("columns", cyan),
Span::raw(" and progress bars, with Rich-compatible "),
Span::styled("[markup]", yellow),
Span::raw("."),
]),
]);
Panel::new(body)
.border(BorderType::Rounded)
.border_style(Style::new().fg(Color::Cyan))
.title(
Title::new(" sparcli ")
.align(Align::Center)
.style(Style::new().fg(Color::Cyan).bold()),
)
.content_align(Align::Center)
.width(96)
.print()
}
fn dashboard() -> Result<()> {
Columns::new()
.add_rendered(overview_table())
.add_rendered(middle_column())
.add_rendered(right_column())
.gap(3)
.separator(BorderType::Single)
.print()
}
fn overview_table() -> Rendered {
let status = |text: &str, color: Color| {
Cell::new(Text::styled(text, Style::new().fg(color).bold()))
};
Table::new()
.title("Overview")
.title_style(Style::new().fg(Color::Magenta).bold())
.border(BorderType::Rounded)
.border_style(Style::new().fg(Color::Magenta))
.header_style(Style::new().fg(Color::Cyan).bold())
.striped(true)
.stripe_style(Style::new().bg(Color::Rgb(40, 40, 60)))
.row_separators(true)
.columns([
Column::new("Service"),
Column::new("Status").align(Align::Center),
Column::new("Uptime").align(Align::Right),
])
.row([
Cell::new("api-gateway"),
status("● OK", Color::Green),
Cell::new("99.98%"),
])
.row([
Cell::new("auth"),
status("● OK", Color::Green),
Cell::new("99.91%"),
])
.row([
Cell::new("billing"),
status("● WARN", Color::Yellow),
Cell::new("97.40%"),
])
.row([
Cell::new("scheduler"),
status("● FAIL", Color::Red),
Cell::new("82.10%"),
])
.render(40)
}
fn middle_column() -> Rendered {
let list = List::ordered(Marker::Number)
.marker_style(Style::new().fg(Color::Yellow).bold())
.item("Compose widgets side by side")
.item("Capture, pad, and align them")
.item("Style with Rich-style markup")
.item("Render to any UTF-8 terminal")
.render(36);
let tree = Tree::new()
.dashes(2)
.connector_style(Style::new().fg(Color::Cyan))
.node(
TreeNode::new("project/")
.child(
TreeNode::new("api/")
.child(TreeNode::new("routes.c"))
.child(TreeNode::new("auth.c")),
)
.child(TreeNode::new("worker.c"))
.child(TreeNode::new("store.c")),
)
.render(18);
let rules = vstack(
&[
rule("Pipeline", BorderType::Single, Color::Magenta),
blank(),
rule("Workers", BorderType::Double, Color::Green),
blank(),
rule("Storage", BorderType::Thick, Color::Yellow),
blank(),
],
0,
);
let tree_and_rules = Columns::new()
.add_rendered(tree)
.add_rendered(rules)
.gap(2)
.render(40);
vstack(&[list, blank(), tree_and_rules], 0)
}
fn rule(title: &str, border: BorderType, color: Color) -> Rendered {
Rule::with_title(Text::styled(title, Style::new().fg(color).bold()))
.border(border)
.style(Style::new().fg(color))
.width(20)
.render(20)
}
fn right_column() -> Rendered {
let kv = KeyValue::new()
.key_style(Style::new().fg(Color::Cyan).bold())
.value_style(Style::new())
.add("host", "localhost")
.add("port", "8080")
.add("scheme", "https")
.add("timeout", "30s")
.render(24);
let badge = |text: &str, color: Color| {
Badge::new(text)
.pad(1)
.style(Style::new().fg(Color::Black).bg(color).bold())
.span()
};
let badges = Rendered::new(vec![
Line::new(vec![
badge("DONE", Color::Green),
Span::raw(" "),
badge("INFO", Color::LightBlue),
]),
Line::default(),
Line::new(vec![
badge("WARN", Color::Yellow),
Span::raw(" "),
badge("FAIL", Color::Red),
]),
]);
let label = |text: &str| {
Rendered::new(vec![Line::styled(
text,
Style::new().fg(Color::Cyan).bold(),
)])
};
let staggered = Columns::new()
.add_rendered(label("Col 1"))
.add_rendered(vstack(&[blank(), label("Col 2")], 0))
.add_rendered(vstack(&[blank(), blank(), label("Col 3")], 0))
.gap(2)
.separator(BorderType::Single)
.render(40);
vstack(&[kv, blank(), badges, blank(), staggered], 0)
}
fn progress() -> Result<()> {
ProgressBar::new()
.label("Building")
.fill_color(Color::Green)
.caps("[", "]")
.width(29)
.show_value(true)
.bar(92.0, 100.0)
.print()
}