use ratatui::style::{Color, Modifier, Style};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Theme {
pub user_color: ColorDef,
pub assistant_color: ColorDef,
pub system_color: ColorDef,
pub tool_color: ColorDef,
pub error_color: ColorDef,
pub border_color: ColorDef,
pub input_border_color: ColorDef,
pub help_border_color: ColorDef,
pub timestamp_color: ColorDef,
pub code_block_color: ColorDef,
pub status_bar_foreground: ColorDef,
pub status_bar_background: ColorDef,
pub background: Option<ColorDef>,
}
impl Default for Theme {
fn default() -> Self {
Self::marketing()
}
}
impl Theme {
pub fn dark() -> Self {
Self {
user_color: ColorDef::Named("green".to_string()),
assistant_color: ColorDef::Named("cyan".to_string()),
system_color: ColorDef::Named("yellow".to_string()),
tool_color: ColorDef::Named("magenta".to_string()),
error_color: ColorDef::Named("red".to_string()),
border_color: ColorDef::Named("cyan".to_string()),
input_border_color: ColorDef::Named("white".to_string()),
help_border_color: ColorDef::Named("yellow".to_string()),
timestamp_color: ColorDef::Named("darkgray".to_string()),
code_block_color: ColorDef::Named("darkgray".to_string()),
status_bar_foreground: ColorDef::Named("black".to_string()),
status_bar_background: ColorDef::Named("white".to_string()),
background: None,
}
}
pub fn light() -> Self {
Self {
user_color: ColorDef::Named("darkgreen".to_string()),
assistant_color: ColorDef::Named("darkblue".to_string()),
system_color: ColorDef::Named("darkyellow".to_string()),
tool_color: ColorDef::Named("darkmagenta".to_string()),
error_color: ColorDef::Named("darkred".to_string()),
border_color: ColorDef::Named("darkgray".to_string()),
input_border_color: ColorDef::Named("black".to_string()),
help_border_color: ColorDef::Named("darkyellow".to_string()),
timestamp_color: ColorDef::Named("gray".to_string()),
code_block_color: ColorDef::Named("gray".to_string()),
status_bar_foreground: ColorDef::Named("white".to_string()),
status_bar_background: ColorDef::Named("black".to_string()),
background: Some(ColorDef::Named("white".to_string())),
}
}
pub fn solarized_dark() -> Self {
Self {
user_color: ColorDef::Rgb(133, 153, 0), assistant_color: ColorDef::Rgb(42, 161, 152), system_color: ColorDef::Rgb(181, 137, 0), tool_color: ColorDef::Rgb(211, 54, 130), error_color: ColorDef::Rgb(220, 50, 47), border_color: ColorDef::Rgb(131, 148, 150), input_border_color: ColorDef::Rgb(238, 232, 213), help_border_color: ColorDef::Rgb(181, 137, 0), timestamp_color: ColorDef::Rgb(101, 123, 131), code_block_color: ColorDef::Rgb(88, 110, 117), status_bar_foreground: ColorDef::Rgb(0, 43, 54), status_bar_background: ColorDef::Rgb(238, 232, 213), background: Some(ColorDef::Rgb(0, 43, 54)), }
}
pub fn solarized_light() -> Self {
Self {
user_color: ColorDef::Rgb(133, 153, 0), assistant_color: ColorDef::Rgb(42, 161, 152), system_color: ColorDef::Rgb(181, 137, 0), tool_color: ColorDef::Rgb(211, 54, 130), error_color: ColorDef::Rgb(220, 50, 47), border_color: ColorDef::Rgb(88, 110, 117), input_border_color: ColorDef::Rgb(147, 161, 161), help_border_color: ColorDef::Rgb(181, 137, 0), timestamp_color: ColorDef::Rgb(131, 148, 150), code_block_color: ColorDef::Rgb(147, 161, 161), status_bar_foreground: ColorDef::Rgb(238, 232, 213), status_bar_background: ColorDef::Rgb(88, 110, 117), background: Some(ColorDef::Rgb(253, 246, 227)), }
}
pub fn marketing() -> Self {
Self {
user_color: ColorDef::Rgb(6, 182, 212), assistant_color: ColorDef::Rgb(34, 211, 238), system_color: ColorDef::Rgb(250, 204, 21), tool_color: ColorDef::Rgb(232, 121, 249), error_color: ColorDef::Rgb(248, 113, 113), border_color: ColorDef::Rgb(31, 41, 55), input_border_color: ColorDef::Rgb(55, 65, 81), help_border_color: ColorDef::Rgb(6, 182, 212), timestamp_color: ColorDef::Rgb(107, 114, 128), code_block_color: ColorDef::Rgb(75, 85, 99), status_bar_foreground: ColorDef::Rgb(17, 24, 39), status_bar_background: ColorDef::Rgb(6, 182, 212), background: Some(ColorDef::Rgb(3, 7, 18)), }
}
pub fn get_role_style(&self, role: &str) -> Style {
let color = match role {
"user" => self.user_color.to_color(),
"assistant" => self.assistant_color.to_color(),
"system" => self.system_color.to_color(),
"tool" => self.tool_color.to_color(),
"error" => self.error_color.to_color(),
_ => Color::White,
};
Style::default().fg(color).add_modifier(Modifier::BOLD)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ColorDef {
Named(String),
Rgb(u8, u8, u8),
Indexed(u8),
}
impl ColorDef {
pub fn to_color(&self) -> Color {
match self {
ColorDef::Named(name) => match name.to_lowercase().as_str() {
"black" => Color::Black,
"red" => Color::Red,
"green" => Color::Green,
"yellow" => Color::Yellow,
"blue" => Color::Blue,
"magenta" => Color::Magenta,
"cyan" => Color::Cyan,
"gray" | "grey" => Color::Gray,
"darkgray" | "dark_gray" | "darkgrey" => Color::DarkGray,
"lightgray" | "light_gray" | "lightgrey" => Color::Gray,
"darkred" | "dark_red" => Color::Red,
"darkgreen" | "dark_green" => Color::Green,
"darkyellow" | "dark_yellow" => Color::Yellow,
"darkblue" | "dark_blue" => Color::Blue,
"darkmagenta" | "dark_magenta" => Color::Magenta,
"darkcyan" | "dark_cyan" => Color::Cyan,
"lightred" | "light_red" => Color::LightRed,
"lightgreen" | "light_green" => Color::LightGreen,
"lightyellow" | "light_yellow" => Color::LightYellow,
"lightblue" | "light_blue" => Color::LightBlue,
"lightmagenta" | "light_magenta" => Color::LightMagenta,
"lightcyan" | "light_cyan" => Color::LightCyan,
"white" => Color::White,
_ => Color::White,
},
ColorDef::Rgb(r, g, b) => Color::Rgb(*r, *g, *b),
ColorDef::Indexed(idx) => Color::Indexed(*idx),
}
}
}
impl From<Color> for ColorDef {
fn from(color: Color) -> Self {
match color {
Color::Black => ColorDef::Named("black".to_string()),
Color::Red => ColorDef::Named("red".to_string()),
Color::Green => ColorDef::Named("green".to_string()),
Color::Yellow => ColorDef::Named("yellow".to_string()),
Color::Blue => ColorDef::Named("blue".to_string()),
Color::Magenta => ColorDef::Named("magenta".to_string()),
Color::Cyan => ColorDef::Named("cyan".to_string()),
Color::Gray => ColorDef::Named("gray".to_string()),
Color::DarkGray => ColorDef::Named("darkgray".to_string()),
Color::LightRed => ColorDef::Named("lightred".to_string()),
Color::LightGreen => ColorDef::Named("lightgreen".to_string()),
Color::LightYellow => ColorDef::Named("lightyellow".to_string()),
Color::LightBlue => ColorDef::Named("lightblue".to_string()),
Color::LightMagenta => ColorDef::Named("lightmagenta".to_string()),
Color::LightCyan => ColorDef::Named("lightcyan".to_string()),
Color::White => ColorDef::Named("white".to_string()),
Color::Rgb(r, g, b) => ColorDef::Rgb(r, g, b),
Color::Indexed(idx) => ColorDef::Indexed(idx),
_ => ColorDef::Named("white".to_string()),
}
}
}
impl ColorDef {
pub fn black() -> Self {
ColorDef::Named("black".to_string())
}
pub fn red() -> Self {
ColorDef::Named("red".to_string())
}
pub fn green() -> Self {
ColorDef::Named("green".to_string())
}
pub fn yellow() -> Self {
ColorDef::Named("yellow".to_string())
}
pub fn blue() -> Self {
ColorDef::Named("blue".to_string())
}
pub fn magenta() -> Self {
ColorDef::Named("magenta".to_string())
}
pub fn cyan() -> Self {
ColorDef::Named("cyan".to_string())
}
pub fn white() -> Self {
ColorDef::Named("white".to_string())
}
pub fn gray() -> Self {
ColorDef::Named("gray".to_string())
}
pub fn dark_gray() -> Self {
ColorDef::Named("darkgray".to_string())
}
pub fn light_gray() -> Self {
ColorDef::Named("gray".to_string())
}
}