use ratatui::style::Color;
use crate::detect::{self, ColorMode};
#[derive(Debug, Clone, Copy)]
pub struct AdaptiveColor {
pub light: Color,
pub dark: Color,
}
impl AdaptiveColor {
pub fn resolve(&self) -> Color {
match detect::detect_color_mode() {
ColorMode::Dark => self.dark,
ColorMode::Light => self.light,
ColorMode::None => Color::Reset,
}
}
}
pub const COLOR_PRIMARY: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(0, 139, 139), dark: Color::Rgb(139, 233, 253), };
pub const COLOR_SECONDARY: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(68, 71, 144), dark: Color::Rgb(189, 147, 249), };
pub const COLOR_ACCENT: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(163, 55, 136), dark: Color::Rgb(255, 121, 198), };
pub const COLOR_SUCCESS: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(40, 130, 40), dark: Color::Rgb(80, 250, 123), };
pub const COLOR_WARNING: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(180, 120, 0), dark: Color::Rgb(241, 250, 140), };
pub const COLOR_ERROR: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(215, 55, 55), dark: Color::Rgb(255, 85, 85), };
pub const COLOR_FG: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(40, 42, 54), dark: Color::Rgb(248, 248, 242), };
pub const COLOR_BG: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(248, 248, 242), dark: Color::Rgb(40, 42, 54), };
pub const COLOR_INACTIVE: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(140, 140, 140), dark: Color::Rgb(98, 114, 164), };
pub const COLOR_HIGHLIGHT: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(230, 230, 230), dark: Color::Rgb(68, 71, 90), };
pub const COLOR_PROGRESS_START: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(100, 60, 180), dark: Color::Rgb(189, 147, 249), };
pub const COLOR_PROGRESS_END: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(0, 139, 139), dark: Color::Rgb(139, 233, 253), };
pub const COLOR_PROGRESS_EMPTY: AdaptiveColor = AdaptiveColor {
light: Color::Rgb(200, 200, 200), dark: Color::Rgb(98, 114, 164), };
pub struct Theme {
pub primary: Color,
pub secondary: Color,
pub accent: Color,
pub success: Color,
pub warning: Color,
pub error: Color,
pub bg: Color,
pub fg: Color,
pub highlight: Color,
pub inactive: Color,
}
impl Theme {
pub fn adaptive() -> Self {
Self {
primary: COLOR_PRIMARY.resolve(),
secondary: COLOR_SECONDARY.resolve(),
accent: COLOR_ACCENT.resolve(),
success: COLOR_SUCCESS.resolve(),
warning: COLOR_WARNING.resolve(),
error: COLOR_ERROR.resolve(),
bg: COLOR_BG.resolve(),
fg: COLOR_FG.resolve(),
highlight: COLOR_HIGHLIGHT.resolve(),
inactive: COLOR_INACTIVE.resolve(),
}
}
}
impl Default for Theme {
fn default() -> Self {
Self {
primary: Color::Cyan,
secondary: Color::Blue,
accent: Color::Magenta,
success: Color::Green,
warning: Color::Yellow,
error: Color::Red,
bg: Color::Black,
fg: Color::White,
highlight: Color::Rgb(50, 50, 50),
inactive: Color::DarkGray,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn theme_default_has_inactive() {
let t = Theme::default();
assert_eq!(t.inactive, Color::DarkGray);
}
#[test]
fn adaptive_color_resolve_does_not_panic() {
let _ = COLOR_PRIMARY.resolve();
let _ = COLOR_ERROR.resolve();
}
#[test]
fn theme_adaptive_does_not_panic() {
let _ = Theme::adaptive();
}
}