use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::{Block, BorderType, Borders};
pub const TEXT: Color = Color::Reset;
pub const MUTED: Color = Color::DarkGray;
pub const ACCENT: Color = Color::Cyan;
pub const OK: Color = Color::Green;
pub const BAD: Color = Color::Red;
pub const WARN: Color = Color::Yellow;
pub const HALTED: Color = Color::Magenta;
pub const REVIEW: Color = Color::Blue;
pub const CURSOR: &str = "\u{258c}";
pub const CONTINUE: &str = "\u{2502}";
pub const PASSED: &str = "\u{2713}";
pub const FAILED: &str = "\u{2717}";
pub const SPINNER: [&str; 8] = [
"\u{280b}", "\u{2819}", "\u{2839}", "\u{2838}", "\u{283c}", "\u{2834}", "\u{2826}", "\u{2827}",
];
pub const RULE: &str = "\u{2500}";
pub const GUTTER: u16 = 1;
pub fn text() -> Style {
Style::default().fg(TEXT)
}
pub fn muted() -> Style {
Style::default().fg(MUTED)
}
pub fn bold() -> Style {
Style::default().add_modifier(Modifier::BOLD)
}
pub fn accent() -> Style {
Style::default().fg(ACCENT)
}
pub fn on(colour: Color) -> Style {
Style::default().fg(colour)
}
pub fn panel(active: bool) -> Block<'static> {
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(if active { accent() } else { muted() })
}
pub fn fit(
mut lines: Vec<ratatui::text::Line<'static>>,
height: u16,
) -> Vec<ratatui::text::Line<'static>> {
use ratatui::text::{Line, Span};
let room = height.saturating_sub(2) as usize;
if lines.len() <= room || room < 4 {
return lines;
}
let footer = lines.pop().unwrap_or_default();
let kept = room - 2;
let hidden = lines.len() - kept;
lines.truncate(kept);
lines.push(Line::from(Span::styled(
format!(
"\u{2026} {hidden} more line{}",
if hidden == 1 { "" } else { "s" }
),
muted(),
)));
lines.push(footer);
lines
}
pub fn centred(area: Rect, width: u16, height: u16) -> Rect {
let width = width.min(area.width);
let height = height.min(area.height);
Rect {
x: area.x + (area.width - width) / 2,
y: area.y + (area.height - height) / 2,
width,
height,
}
}
pub fn rule(width: u16) -> ratatui::text::Line<'static> {
ratatui::text::Line::from(ratatui::text::Span::styled(
RULE.repeat(width as usize),
muted(),
))
}
pub fn labelled_rule(width: u16, label: &str, colour: Color) -> ratatui::text::Line<'static> {
use ratatui::text::{Line, Span};
let width = width as usize;
let label = label.trim();
if label.is_empty() || width < 12 {
return rule(width as u16);
}
let after = 2;
let room = width - after - 2;
let label: String = if label.chars().count() > room {
label
.chars()
.take(room.saturating_sub(1))
.chain(std::iter::once('\u{2026}'))
.collect()
} else {
label.to_string()
};
let before = width - label.chars().count() - after - 2;
Line::from(vec![
Span::styled(RULE.repeat(before), muted()),
Span::styled(format!(" {label} "), on(colour)),
Span::styled(RULE.repeat(after), muted()),
])
}
pub fn inset(area: Rect) -> Rect {
Rect {
x: area.x.saturating_add(GUTTER),
width: area.width.saturating_sub(GUTTER),
..area
}
}