use ratatui::style::{Color, Modifier, Style};
#[derive(Debug, Clone)]
pub struct Theme {
pub primary: Color,
pub secondary: Color,
pub accent: Color,
pub bg: Color,
pub fg: Color,
pub success: Color,
pub warning: Color,
pub error: Color,
pub muted: Color,
pub border: Color,
pub highlight: Color,
}
impl Default for Theme {
fn default() -> Self {
Self {
primary: Color::Cyan,
secondary: Color::Blue,
accent: Color::Magenta,
bg: Color::Black,
fg: Color::White,
success: Color::Green,
warning: Color::Yellow,
error: Color::Red,
muted: Color::DarkGray,
border: Color::Gray,
highlight: Color::LightCyan,
}
}
}
impl Theme {
pub fn light() -> Self {
Self {
primary: Color::Blue,
secondary: Color::DarkGray,
accent: Color::Magenta,
bg: Color::White,
fg: Color::Black,
success: Color::Green,
warning: Color::Yellow,
error: Color::Red,
muted: Color::Gray,
border: Color::DarkGray,
highlight: Color::LightBlue,
}
}
pub fn monokai() -> Self {
Self {
primary: Color::Rgb(102, 217, 239), secondary: Color::Rgb(249, 38, 114), accent: Color::Rgb(166, 226, 46), bg: Color::Rgb(39, 40, 34), fg: Color::Rgb(248, 248, 242), success: Color::Rgb(166, 226, 46), warning: Color::Rgb(230, 219, 116), error: Color::Rgb(249, 38, 114), muted: Color::Rgb(117, 113, 94), border: Color::Rgb(73, 72, 62), highlight: Color::Rgb(73, 72, 62), }
}
pub fn solarized() -> Self {
Self {
primary: Color::Rgb(38, 139, 210), secondary: Color::Rgb(42, 161, 152), accent: Color::Rgb(211, 54, 130), bg: Color::Rgb(0, 43, 54), fg: Color::Rgb(131, 148, 150), success: Color::Rgb(133, 153, 0), warning: Color::Rgb(181, 137, 0), error: Color::Rgb(220, 50, 47), muted: Color::Rgb(88, 110, 117), border: Color::Rgb(7, 54, 66), highlight: Color::Rgb(7, 54, 66), }
}
pub fn primary(&self) -> Style {
Style::default().fg(self.primary)
}
pub fn secondary(&self) -> Style {
Style::default().fg(self.secondary)
}
pub fn accent(&self) -> Style {
Style::default().fg(self.accent)
}
pub fn success(&self) -> Style {
Style::default().fg(self.success)
}
pub fn warning(&self) -> Style {
Style::default().fg(self.warning)
}
pub fn error(&self) -> Style {
Style::default().fg(self.error)
}
pub fn muted(&self) -> Style {
Style::default().fg(self.muted)
}
pub fn border(&self) -> Style {
Style::default().fg(self.border)
}
pub fn highlight(&self) -> Style {
Style::default()
.fg(self.bg)
.bg(self.highlight)
.add_modifier(Modifier::BOLD)
}
pub fn title(&self) -> Style {
Style::default()
.fg(self.primary)
.add_modifier(Modifier::BOLD)
}
pub fn subtitle(&self) -> Style {
Style::default()
.fg(self.secondary)
.add_modifier(Modifier::ITALIC)
}
pub fn bold(&self) -> Style {
Style::default().fg(self.fg).add_modifier(Modifier::BOLD)
}
pub fn dim(&self) -> Style {
Style::default().fg(self.muted).add_modifier(Modifier::DIM)
}
pub fn normal(&self) -> Style {
Style::default().fg(self.fg).bg(self.bg)
}
pub fn modal_bg(&self) -> Style {
Style::default().fg(self.fg).bg(Color::DarkGray)
}
pub fn modal_border(&self) -> Style {
Style::default().fg(self.primary)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_theme() {
let theme = Theme::default();
assert_eq!(theme.primary, Color::Cyan);
assert_eq!(theme.bg, Color::Black);
assert_eq!(theme.fg, Color::White);
assert_eq!(theme.success, Color::Green);
assert_eq!(theme.error, Color::Red);
}
#[test]
fn test_light_theme() {
let theme = Theme::light();
assert_eq!(theme.primary, Color::Blue);
assert_eq!(theme.bg, Color::White);
assert_eq!(theme.fg, Color::Black);
}
#[test]
fn test_monokai_theme() {
let theme = Theme::monokai();
assert_eq!(theme.primary, Color::Rgb(102, 217, 239));
assert_eq!(theme.bg, Color::Rgb(39, 40, 34));
assert_eq!(theme.fg, Color::Rgb(248, 248, 242));
}
#[test]
fn test_solarized_theme() {
let theme = Theme::solarized();
assert_eq!(theme.primary, Color::Rgb(38, 139, 210));
assert_eq!(theme.bg, Color::Rgb(0, 43, 54));
}
#[test]
fn test_style_methods() {
let theme = Theme::default();
let primary_style = theme.primary();
assert!(matches!(primary_style.fg, Some(Color::Cyan)));
let success_style = theme.success();
assert!(matches!(success_style.fg, Some(Color::Green)));
let error_style = theme.error();
assert!(matches!(error_style.fg, Some(Color::Red)));
}
#[test]
fn test_highlight_style() {
let theme = Theme::default();
let highlight = theme.highlight();
assert_eq!(highlight.fg, Some(theme.bg));
assert_eq!(highlight.bg, Some(theme.highlight));
}
#[test]
fn test_title_style_has_bold() {
let theme = Theme::default();
let title = theme.title();
assert_eq!(title.fg, Some(theme.primary));
assert!(title.add_modifier.contains(Modifier::BOLD));
}
#[test]
fn test_subtitle_style_has_italic() {
let theme = Theme::default();
let subtitle = theme.subtitle();
assert_eq!(subtitle.fg, Some(theme.secondary));
assert!(subtitle.add_modifier.contains(Modifier::ITALIC));
}
#[test]
fn test_normal_style() {
let theme = Theme::default();
let normal = theme.normal();
assert_eq!(normal.fg, Some(theme.fg));
assert_eq!(normal.bg, Some(theme.bg));
}
}