#![allow(dead_code)]
use crate::tui::theme::Theme;
use ratatui::{
layout::Rect,
style::{Modifier, Style},
text::{Line, Span, Text},
widgets::Paragraph,
Frame,
};
pub struct StatusBarProps<'a> {
pub route: &'a str,
pub tokens_pct: Option<u8>,
pub tokens_abs: Option<&'a str>,
pub cost: Option<&'a str>,
pub shortcuts: &'a str,
pub tip: Option<&'a str>,
}
pub fn render(frame: &mut Frame, area: Rect, props: &StatusBarProps, theme: &Theme) {
let badge_style = Style::default()
.bg(theme.primary)
.fg(theme.on_primary)
.add_modifier(Modifier::BOLD);
let strong = Style::default().fg(theme.text_strong);
let muted = Style::default().fg(theme.text_muted);
let mut spans_line1: Vec<Span> = vec![
Span::styled(" ", badge_style),
Span::styled(props.route.to_owned(), badge_style),
Span::styled(" ", badge_style),
Span::styled(" ", strong), ];
let mut metrics: Vec<String> = Vec::new();
if let (Some(pct), Some(abs)) = (props.tokens_pct, props.tokens_abs) {
metrics.push(format!("{}% · {}", pct, abs));
} else if let Some(pct) = props.tokens_pct {
metrics.push(format!("{}%", pct));
} else if let Some(abs) = props.tokens_abs {
metrics.push(abs.to_owned());
}
if let Some(cost) = props.cost {
metrics.push(cost.to_owned());
}
if !metrics.is_empty() {
let metrics_str = metrics.join(" · ");
spans_line1.push(Span::styled(metrics_str, muted));
spans_line1.push(Span::styled(" ", muted)); }
if !props.shortcuts.is_empty() {
spans_line1.push(Span::styled(props.shortcuts.to_owned(), muted));
}
let line1 = Line::from(spans_line1);
let lines: Vec<Line> = if let Some(tip_text) = props.tip {
let tip_badge_style = Style::default()
.bg(theme.primary)
.fg(theme.on_primary)
.add_modifier(Modifier::BOLD);
let line2 = Line::from(vec![
Span::styled(" Tip ", tip_badge_style),
Span::styled(" ", muted),
Span::styled(tip_text.to_owned(), muted),
]);
vec![line1, line2]
} else {
vec![line1]
};
let text = Text::from(lines);
let paragraph = Paragraph::new(text);
frame.render_widget(paragraph, area);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tui::theme::{theme, ColorDepth};
use ratatui::{backend::TestBackend, Terminal};
fn make_terminal(width: u16, height: u16) -> Terminal<TestBackend> {
Terminal::new(TestBackend::new(width, height)).unwrap()
}
#[test]
fn render_todos_campos_80x3() {
let mut terminal = make_terminal(80, 3);
let t = theme(ColorDepth::TrueColor);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 80, 3);
let props = StatusBarProps {
route: "/techspec",
tokens_pct: Some(42),
tokens_abs: Some("12 k"),
cost: Some("$0.042"),
shortcuts: "↑↓ navegar q sair",
tip: Some("Use Tab para alternar painéis"),
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_opcionais_none_80x3() {
let mut terminal = make_terminal(80, 3);
let t = theme(ColorDepth::Ansi16);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 80, 3);
let props = StatusBarProps {
route: "/home",
tokens_pct: None,
tokens_abs: None,
cost: None,
shortcuts: "",
tip: None,
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_todos_campos_40x3() {
let mut terminal = make_terminal(40, 3);
let t = theme(ColorDepth::Ansi256);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 40, 3);
let props = StatusBarProps {
route: "/prd",
tokens_pct: Some(99),
tokens_abs: Some("200 k"),
cost: Some("$1.20"),
shortcuts: "q sair",
tip: Some("Dica curta"),
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_opcionais_none_40x3() {
let mut terminal = make_terminal(40, 3);
let t = theme(ColorDepth::TrueColor);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 40, 3);
let props = StatusBarProps {
route: "/tasks",
tokens_pct: None,
tokens_abs: None,
cost: None,
shortcuts: "↵ confirmar",
tip: None,
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_apenas_tokens_pct() {
let mut terminal = make_terminal(80, 2);
let t = theme(ColorDepth::Ansi16);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 80, 2);
let props = StatusBarProps {
route: "/execution",
tokens_pct: Some(75),
tokens_abs: None,
cost: None,
shortcuts: "Ctrl+C cancelar",
tip: None,
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_apenas_tokens_abs() {
let mut terminal = make_terminal(80, 2);
let t = theme(ColorDepth::Ansi256);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 80, 2);
let props = StatusBarProps {
route: "/review",
tokens_pct: None,
tokens_abs: Some("8 k"),
cost: None,
shortcuts: "",
tip: None,
};
render(f, area, &props, &t);
})
.unwrap();
}
#[test]
fn render_apenas_cost() {
let mut terminal = make_terminal(80, 2);
let t = theme(ColorDepth::TrueColor);
terminal
.draw(|f| {
let area = Rect::new(0, 0, 80, 2);
let props = StatusBarProps {
route: "/memory",
tokens_pct: None,
tokens_abs: None,
cost: Some("$0.001"),
shortcuts: "↑↓ rolar",
tip: Some("Memória compactada com sucesso"),
};
render(f, area, &props, &t);
})
.unwrap();
}
}