use colored::CustomColor;
use std::sync::atomic::{AtomicU8, Ordering};
static CURRENT_THEME: AtomicU8 = AtomicU8::new(0);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ThemeId {
#[default]
Amber,
Ocean,
Minimal,
HighContrast,
Dracula,
Monokai,
SolarizedDark,
SolarizedLight,
Nord,
Gruvbox,
}
impl ThemeId {
pub fn from_u8(value: u8) -> Self {
match value {
0 => ThemeId::Amber,
1 => ThemeId::Ocean,
2 => ThemeId::Minimal,
3 => ThemeId::HighContrast,
4 => ThemeId::Dracula,
5 => ThemeId::Monokai,
6 => ThemeId::SolarizedDark,
7 => ThemeId::SolarizedLight,
8 => ThemeId::Nord,
9 => ThemeId::Gruvbox,
_ => ThemeId::Amber,
}
}
pub fn to_u8(self) -> u8 {
match self {
ThemeId::Amber => 0,
ThemeId::Ocean => 1,
ThemeId::Minimal => 2,
ThemeId::HighContrast => 3,
ThemeId::Dracula => 4,
ThemeId::Monokai => 5,
ThemeId::SolarizedDark => 6,
ThemeId::SolarizedLight => 7,
ThemeId::Nord => 8,
ThemeId::Gruvbox => 9,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ThemeColors {
pub primary: CustomColor,
pub success: CustomColor,
pub warning: CustomColor,
pub error: CustomColor,
pub muted: CustomColor,
pub accent: CustomColor,
pub tool: CustomColor,
pub path: CustomColor,
}
impl ThemeColors {
pub const AMBER: ThemeColors = ThemeColors {
primary: CustomColor {
r: 212,
g: 163,
b: 115,
}, success: CustomColor {
r: 144,
g: 190,
b: 109,
}, warning: CustomColor {
r: 188,
g: 108,
b: 37,
}, error: CustomColor {
r: 100,
g: 100,
b: 120,
}, muted: CustomColor {
r: 128,
g: 128,
b: 128,
}, accent: CustomColor {
r: 184,
g: 115,
b: 51,
}, tool: CustomColor {
r: 184,
g: 115,
b: 51,
}, path: CustomColor {
r: 143,
g: 151,
b: 121,
}, };
pub const OCEAN: ThemeColors = ThemeColors {
primary: CustomColor {
r: 100,
g: 149,
b: 237,
}, success: CustomColor {
r: 32,
g: 178,
b: 170,
}, warning: CustomColor {
r: 255,
g: 165,
b: 0,
}, error: CustomColor {
r: 255,
g: 99,
b: 71,
}, muted: CustomColor {
r: 119,
g: 136,
b: 153,
}, accent: CustomColor {
r: 0,
g: 206,
b: 209,
}, tool: CustomColor {
r: 72,
g: 209,
b: 204,
}, path: CustomColor {
r: 176,
g: 196,
b: 222,
}, };
pub const MINIMAL: ThemeColors = ThemeColors {
primary: CustomColor {
r: 220,
g: 220,
b: 220,
}, success: CustomColor {
r: 180,
g: 180,
b: 180,
}, warning: CustomColor {
r: 160,
g: 160,
b: 160,
}, error: CustomColor {
r: 140,
g: 140,
b: 140,
}, muted: CustomColor {
r: 100,
g: 100,
b: 100,
}, accent: CustomColor {
r: 200,
g: 200,
b: 200,
}, tool: CustomColor {
r: 180,
g: 180,
b: 180,
}, path: CustomColor {
r: 160,
g: 160,
b: 160,
}, };
pub const DRACULA: ThemeColors = ThemeColors {
primary: CustomColor {
r: 189,
g: 147,
b: 249,
}, success: CustomColor {
r: 80,
g: 250,
b: 123,
}, warning: CustomColor {
r: 241,
g: 250,
b: 140,
}, error: CustomColor {
r: 255,
g: 85,
b: 85,
}, muted: CustomColor {
r: 98,
g: 114,
b: 164,
}, accent: CustomColor {
r: 255,
g: 121,
b: 198,
}, tool: CustomColor {
r: 139,
g: 233,
b: 253,
}, path: CustomColor {
r: 241,
g: 250,
b: 140,
}, };
pub const MONOKAI: ThemeColors = ThemeColors {
primary: CustomColor {
r: 102,
g: 217,
b: 239,
}, success: CustomColor {
r: 166,
g: 226,
b: 46,
}, warning: CustomColor {
r: 253,
g: 151,
b: 31,
}, error: CustomColor {
r: 249,
g: 38,
b: 114,
}, muted: CustomColor {
r: 117,
g: 113,
b: 94,
}, accent: CustomColor {
r: 174,
g: 129,
b: 255,
}, tool: CustomColor {
r: 166,
g: 226,
b: 46,
}, path: CustomColor {
r: 230,
g: 219,
b: 116,
}, };
pub const SOLARIZED_DARK: ThemeColors = ThemeColors {
primary: CustomColor {
r: 38,
g: 139,
b: 210,
}, success: CustomColor {
r: 133,
g: 153,
b: 0,
}, warning: CustomColor {
r: 181,
g: 137,
b: 0,
}, error: CustomColor {
r: 220,
g: 50,
b: 47,
}, muted: CustomColor {
r: 88,
g: 110,
b: 117,
}, accent: CustomColor {
r: 108,
g: 113,
b: 196,
}, tool: CustomColor {
r: 42,
g: 161,
b: 152,
}, path: CustomColor {
r: 147,
g: 161,
b: 161,
}, };
pub const SOLARIZED_LIGHT: ThemeColors = ThemeColors {
primary: CustomColor {
r: 38,
g: 139,
b: 210,
}, success: CustomColor {
r: 133,
g: 153,
b: 0,
}, warning: CustomColor {
r: 181,
g: 137,
b: 0,
}, error: CustomColor {
r: 220,
g: 50,
b: 47,
}, muted: CustomColor {
r: 101,
g: 123,
b: 131,
}, accent: CustomColor {
r: 108,
g: 113,
b: 196,
}, tool: CustomColor {
r: 42,
g: 161,
b: 152,
}, path: CustomColor {
r: 88,
g: 110,
b: 117,
}, };
pub const NORD: ThemeColors = ThemeColors {
primary: CustomColor {
r: 136,
g: 192,
b: 208,
}, success: CustomColor {
r: 163,
g: 190,
b: 140,
}, warning: CustomColor {
r: 235,
g: 203,
b: 139,
}, error: CustomColor {
r: 191,
g: 97,
b: 106,
}, muted: CustomColor {
r: 76,
g: 86,
b: 106,
}, accent: CustomColor {
r: 180,
g: 142,
b: 173,
}, tool: CustomColor {
r: 129,
g: 161,
b: 193,
}, path: CustomColor {
r: 143,
g: 188,
b: 187,
}, };
pub const GRUVBOX: ThemeColors = ThemeColors {
primary: CustomColor {
r: 131,
g: 165,
b: 152,
}, success: CustomColor {
r: 184,
g: 187,
b: 38,
}, warning: CustomColor {
r: 250,
g: 189,
b: 47,
}, error: CustomColor {
r: 251,
g: 73,
b: 52,
}, muted: CustomColor {
r: 146,
g: 131,
b: 116,
}, accent: CustomColor {
r: 211,
g: 134,
b: 155,
}, tool: CustomColor {
r: 142,
g: 192,
b: 124,
}, path: CustomColor {
r: 254,
g: 128,
b: 25,
}, };
pub const HIGH_CONTRAST: ThemeColors = ThemeColors {
primary: CustomColor {
r: 255,
g: 255,
b: 255,
}, success: CustomColor { r: 0, g: 255, b: 0 }, warning: CustomColor {
r: 255,
g: 255,
b: 0,
}, error: CustomColor { r: 255, g: 0, b: 0 }, muted: CustomColor {
r: 192,
g: 192,
b: 192,
}, accent: CustomColor {
r: 0,
g: 255,
b: 255,
}, tool: CustomColor {
r: 255,
g: 0,
b: 255,
}, path: CustomColor {
r: 0,
g: 255,
b: 255,
}, };
}
pub fn set_theme(theme: ThemeId) {
CURRENT_THEME.store(theme.to_u8(), Ordering::SeqCst);
}
pub fn current_theme_id() -> ThemeId {
ThemeId::from_u8(CURRENT_THEME.load(Ordering::SeqCst))
}
pub fn current_theme() -> ThemeColors {
theme_colors(current_theme_id())
}
pub fn theme_colors(id: ThemeId) -> ThemeColors {
match id {
ThemeId::Amber => ThemeColors::AMBER,
ThemeId::Ocean => ThemeColors::OCEAN,
ThemeId::Minimal => ThemeColors::MINIMAL,
ThemeId::HighContrast => ThemeColors::HIGH_CONTRAST,
ThemeId::Dracula => ThemeColors::DRACULA,
ThemeId::Monokai => ThemeColors::MONOKAI,
ThemeId::SolarizedDark => ThemeColors::SOLARIZED_DARK,
ThemeId::SolarizedLight => ThemeColors::SOLARIZED_LIGHT,
ThemeId::Nord => ThemeColors::NORD,
ThemeId::Gruvbox => ThemeColors::GRUVBOX,
}
}
pub fn theme_from_name(name: &str) -> Option<ThemeId> {
match name.to_lowercase().as_str() {
"amber" => Some(ThemeId::Amber),
"ocean" => Some(ThemeId::Ocean),
"minimal" => Some(ThemeId::Minimal),
"highcontrast" | "high-contrast" | "high_contrast" => Some(ThemeId::HighContrast),
"dracula" => Some(ThemeId::Dracula),
"monokai" => Some(ThemeId::Monokai),
"solarized-dark" | "solarizeddark" | "solarized_dark" => Some(ThemeId::SolarizedDark),
"solarized-light" | "solarizedlight" | "solarized_light" => Some(ThemeId::SolarizedLight),
"nord" => Some(ThemeId::Nord),
"gruvbox" => Some(ThemeId::Gruvbox),
_ => None,
}
}
pub fn available_themes() -> Vec<&'static str> {
vec![
"amber",
"ocean",
"minimal",
"high-contrast",
"dracula",
"monokai",
"solarized-dark",
"solarized-light",
"nord",
"gruvbox",
]
}
#[cfg(test)]
#[path = "../../tests/unit/ui/theme/theme_test.rs"]
mod tests;