use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, BorderType, Borders, Paragraph};
use crate::theme;
pub const LIST_CURSOR: &str = "❯ ";
pub fn list_cursor_style() -> Style {
Style::default()
.fg(theme::highlight())
.add_modifier(Modifier::BOLD)
}
pub fn checkbox(checked: bool) -> Span<'static> {
let (mark, color) = if checked {
("[x] ", theme::selected())
} else {
("[ ] ", theme::muted())
};
Span::styled(mark.to_string(), Style::default().fg(color))
}
pub fn item_title_style(checked: bool) -> Style {
if checked {
Style::default().fg(theme::selected())
} else {
Style::default().fg(theme::muted())
}
}
pub fn item_desc_style() -> Style {
Style::default()
.fg(theme::muted())
.add_modifier(Modifier::DIM)
}
pub fn status_icon(ok: bool) -> Span<'static> {
let (icon, color) = if ok {
("✓ ", theme::success())
} else {
("✗ ", theme::warning())
};
Span::styled(icon.to_string(), Style::default().fg(color))
}
pub fn wrapping_index(current: usize, delta: isize, len: usize) -> Option<usize> {
if len == 0 {
return None;
}
let len_i = len as isize;
Some((current as isize + delta).rem_euclid(len_i) as usize)
}
pub fn input_paragraph(
value: &str,
placeholder: &str,
active: bool,
title: &str,
) -> Paragraph<'static> {
let cursor = Span::styled("▏".to_string(), Style::default().fg(theme::text()));
let mut spans: Vec<Span<'static>> = Vec::new();
if value.is_empty() {
if active {
spans.push(cursor);
}
spans.push(Span::styled(
placeholder.to_string(),
Style::default().fg(theme::muted()),
));
} else {
spans.push(Span::styled(
value.to_string(),
Style::default().fg(theme::text()),
));
if active {
spans.push(cursor);
}
}
let border = if active {
theme::accent()
} else {
theme::muted()
};
let block = Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(border))
.title(Span::styled(
title.to_string(),
Style::default()
.fg(theme::accent())
.add_modifier(Modifier::BOLD),
));
Paragraph::new(Line::from(spans)).block(block)
}
pub fn key_hint_line(items: &[(&str, &str)]) -> Line<'static> {
let key_style = Style::default()
.fg(theme::text())
.bg(theme::surface())
.add_modifier(Modifier::BOLD);
let label_style = Style::default().fg(theme::muted());
let mut spans: Vec<Span<'static>> = Vec::with_capacity(items.len() * 3);
for (index, (key, label)) in items.iter().enumerate() {
if index > 0 {
spans.push(Span::raw(" "));
}
spans.push(Span::styled(format!(" {key} "), key_style));
spans.push(Span::styled(format!(" {label}"), label_style));
}
Line::from(spans)
}