use ratatui::style::{Color, Modifier, Style};
use ratatui::symbols;
use ratatui::widgets::BorderType;
#[derive(Debug, Clone, Copy)]
pub struct Palette {
pub primary: Color,
pub secondary: Color,
pub surface: Color,
pub on_surface: Color,
pub on_surface_muted: Color,
pub border: Color,
pub border_focused: Color,
pub success: Color,
pub warning: Color,
pub error: Color,
}
impl Default for Palette {
fn default() -> Self {
Self::dark()
}
}
impl Palette {
pub fn dark() -> Self {
Self {
primary: Color::Rgb(129, 199, 132), secondary: Color::Rgb(144, 202, 249), surface: Color::Rgb(40, 42, 54), on_surface: Color::Rgb(248, 248, 242), on_surface_muted: Color::Rgb(120, 144, 156), border: Color::Rgb(96, 125, 139), border_focused: Color::Rgb(129, 199, 132), success: Color::Rgb(102, 187, 106), warning: Color::Rgb(255, 183, 77), error: Color::Rgb(239, 83, 80), }
}
}
pub const ROUNDED_BORDERS: symbols::border::Set = symbols::border::ROUNDED;
pub const fn rounded_border_type() -> BorderType {
BorderType::Rounded
}
#[derive(Debug, Clone)]
pub struct Theme {
pub palette: Palette,
pub user_message: Style,
pub assistant_message: Style,
pub system_message: Style,
pub code_block: Style,
pub success: Style,
pub warning: Style,
pub error: Style,
pub energy_high: Style,
pub energy_medium: Style,
pub energy_low: Style,
pub border: Style,
pub highlight: Style,
pub muted: Style,
pub cursor: Style,
pub tab_active: Style,
pub tab_inactive: Style,
pub user_message_bg: Style,
}
impl Default for Theme {
fn default() -> Self {
Self::dark()
}
}
impl Theme {
pub fn dark() -> Self {
let palette = Palette::dark();
Self {
palette,
user_message: Style::default()
.fg(palette.primary)
.add_modifier(Modifier::BOLD),
assistant_message: Style::default().fg(palette.secondary),
system_message: Style::default().fg(Color::Rgb(176, 190, 197)),
code_block: Style::default().fg(palette.on_surface).bg(palette.surface),
success: Style::default().fg(palette.success),
warning: Style::default().fg(palette.warning),
error: Style::default().fg(palette.error),
energy_high: Style::default()
.fg(palette.error)
.add_modifier(Modifier::BOLD),
energy_medium: Style::default().fg(palette.warning),
energy_low: Style::default()
.fg(palette.success)
.add_modifier(Modifier::BOLD),
border: Style::default().fg(palette.border),
highlight: Style::default()
.fg(Color::Rgb(224, 247, 250))
.bg(Color::Rgb(55, 71, 79))
.add_modifier(Modifier::BOLD),
muted: Style::default().fg(palette.on_surface_muted),
cursor: Style::default()
.fg(Color::Rgb(129, 212, 250))
.add_modifier(Modifier::SLOW_BLINK),
tab_active: Style::default()
.fg(palette.primary)
.add_modifier(Modifier::BOLD),
tab_inactive: Style::default().fg(palette.on_surface_muted),
user_message_bg: Style::default().bg(Color::Rgb(30, 35, 40)), }
}
pub fn energy_style(&self, energy: f32) -> Style {
if energy < 0.1 {
self.energy_low
} else if energy < 0.5 {
self.energy_medium
} else {
self.energy_high
}
}
pub fn status_style(&self, status: &str) -> Style {
match status.to_lowercase().as_str() {
"completed" | "stable" | "ok" => self.success,
"running" | "pending" | "converging" => self.warning,
"failed" | "error" | "escalated" => self.error,
_ => self.muted,
}
}
}
pub mod icons {
pub const USER: &str = "đ§";
pub const ASSISTANT: &str = "đ¤";
pub const SYSTEM: &str = "âšī¸";
pub const SUCCESS: &str = "â";
pub const FAILURE: &str = "â";
pub const WARNING: &str = "â ";
pub const PENDING: &str = "â";
pub const RUNNING: &str = "â";
pub const COMPLETED: &str = "â";
pub const ROCKET: &str = "đ";
pub const TREE: &str = "đŗ";
pub const FILE: &str = "đ";
pub const FOLDER: &str = "đ";
pub const ENERGY: &str = "âĄ";
pub const STABLE: &str = "đ";
pub const CURSOR: &str = "â";
pub const TREE_BRANCH: &str = "ââ";
pub const TREE_LAST: &str = "ââ";
pub const TREE_LINE: &str = "â ";
pub const TREE_SPACE: &str = " ";
}