winbrew_ui/
theme.rs

1use comfy_table::{Cell, Color};
2use console::Style;
3use indicatif::ProgressStyle;
4use std::sync::Arc;
5
6pub const DEFAULT_TABLE_WIDTH: u16 = 80;
7
8pub fn terminal_width() -> u16 {
9    terminal_size::terminal_size()
10        .map(|(terminal_size::Width(width), _)| width)
11        .unwrap_or(DEFAULT_TABLE_WIDTH)
12}
13
14pub const SPINNER_TICK_MS: u64 = 80;
15
16const SPINNER_TEMPLATE_COLOR: &str = "{spinner:.green} {msg}";
17const SPINNER_TEMPLATE_PLAIN: &str = "{spinner} {msg}";
18
19const PROGRESS_TEMPLATE_COLOR: &str =
20    "{spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
21const PROGRESS_TEMPLATE_PLAIN: &str = "{spinner} [{bar:40}] {bytes}/{total_bytes} ({eta})";
22
23const PROGRESS_CHARS: &str = "█▉▊▋▌▍▎▏  ";
24
25pub fn header_cell(label: &str, color_enabled: bool, fg: Color) -> Cell {
26    let cell = Cell::new(label);
27    if color_enabled { cell.fg(fg) } else { cell }
28}
29
30pub fn make_spinner_style(color_enabled: bool) -> Arc<ProgressStyle> {
31    let template = if color_enabled {
32        SPINNER_TEMPLATE_COLOR
33    } else {
34        SPINNER_TEMPLATE_PLAIN
35    };
36
37    let ticks: &[&str] = if color_enabled {
38        &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", ""]
39    } else {
40        &["-", "\\", "|", "/", "-"]
41    };
42
43    Arc::new(
44        ProgressStyle::with_template(template)
45            .expect("spinner template must be valid")
46            .tick_strings(ticks),
47    )
48}
49
50pub fn make_progress_style(color_enabled: bool) -> Arc<ProgressStyle> {
51    let template = if color_enabled {
52        PROGRESS_TEMPLATE_COLOR
53    } else {
54        PROGRESS_TEMPLATE_PLAIN
55    };
56
57    Arc::new(
58        ProgressStyle::with_template(template)
59            .expect("progress template must be valid")
60            .progress_chars(PROGRESS_CHARS),
61    )
62}
63
64pub fn styled_line(value: bool, icon: &str, msg: &str, style: Style) -> String {
65    if value {
66        let level = style.clone().bold().apply_to(icon);
67        let body = style.apply_to(msg);
68        format!("{level} {body}")
69    } else {
70        format!("{icon} {msg}")
71    }
72}