pub mod palette;
pub use palette::Palette;
use crate::Color;
use std::borrow::Cow;
use std::fmt;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq)]
pub enum Theme {
Light,
Dark,
Dracula,
Nord,
SolarizedLight,
SolarizedDark,
GruvboxLight,
GruvboxDark,
CatppuccinLatte,
CatppuccinFrappe,
CatppuccinMacchiato,
CatppuccinMocha,
TokyoNight,
TokyoNightStorm,
TokyoNightLight,
KanagawaWave,
KanagawaDragon,
KanagawaLotus,
Moonfly,
Nightfly,
Oxocarbon,
Ferra,
Custom(Arc<Custom>),
}
impl Theme {
pub const ALL: &'static [Self] = &[
Self::Light,
Self::Dark,
Self::Dracula,
Self::Nord,
Self::SolarizedLight,
Self::SolarizedDark,
Self::GruvboxLight,
Self::GruvboxDark,
Self::CatppuccinLatte,
Self::CatppuccinFrappe,
Self::CatppuccinMacchiato,
Self::CatppuccinMocha,
Self::TokyoNight,
Self::TokyoNightStorm,
Self::TokyoNightLight,
Self::KanagawaWave,
Self::KanagawaDragon,
Self::KanagawaLotus,
Self::Moonfly,
Self::Nightfly,
Self::Oxocarbon,
Self::Ferra,
];
pub fn custom(
name: impl Into<Cow<'static, str>>,
palette: Palette,
) -> Self {
Self::custom_with_fn(name, palette, palette::Extended::generate)
}
pub fn custom_with_fn(
name: impl Into<Cow<'static, str>>,
palette: Palette,
generate: impl FnOnce(Palette) -> palette::Extended,
) -> Self {
Self::Custom(Arc::new(Custom::with_fn(name, palette, generate)))
}
pub fn palette(&self) -> Palette {
match self {
Self::Light => Palette::LIGHT,
Self::Dark => Palette::DARK,
Self::Dracula => Palette::DRACULA,
Self::Nord => Palette::NORD,
Self::SolarizedLight => Palette::SOLARIZED_LIGHT,
Self::SolarizedDark => Palette::SOLARIZED_DARK,
Self::GruvboxLight => Palette::GRUVBOX_LIGHT,
Self::GruvboxDark => Palette::GRUVBOX_DARK,
Self::CatppuccinLatte => Palette::CATPPUCCIN_LATTE,
Self::CatppuccinFrappe => Palette::CATPPUCCIN_FRAPPE,
Self::CatppuccinMacchiato => Palette::CATPPUCCIN_MACCHIATO,
Self::CatppuccinMocha => Palette::CATPPUCCIN_MOCHA,
Self::TokyoNight => Palette::TOKYO_NIGHT,
Self::TokyoNightStorm => Palette::TOKYO_NIGHT_STORM,
Self::TokyoNightLight => Palette::TOKYO_NIGHT_LIGHT,
Self::KanagawaWave => Palette::KANAGAWA_WAVE,
Self::KanagawaDragon => Palette::KANAGAWA_DRAGON,
Self::KanagawaLotus => Palette::KANAGAWA_LOTUS,
Self::Moonfly => Palette::MOONFLY,
Self::Nightfly => Palette::NIGHTFLY,
Self::Oxocarbon => Palette::OXOCARBON,
Self::Ferra => Palette::FERRA,
Self::Custom(custom) => custom.palette,
}
}
pub fn extended_palette(&self) -> &palette::Extended {
match self {
Self::Light => &palette::EXTENDED_LIGHT,
Self::Dark => &palette::EXTENDED_DARK,
Self::Dracula => &palette::EXTENDED_DRACULA,
Self::Nord => &palette::EXTENDED_NORD,
Self::SolarizedLight => &palette::EXTENDED_SOLARIZED_LIGHT,
Self::SolarizedDark => &palette::EXTENDED_SOLARIZED_DARK,
Self::GruvboxLight => &palette::EXTENDED_GRUVBOX_LIGHT,
Self::GruvboxDark => &palette::EXTENDED_GRUVBOX_DARK,
Self::CatppuccinLatte => &palette::EXTENDED_CATPPUCCIN_LATTE,
Self::CatppuccinFrappe => &palette::EXTENDED_CATPPUCCIN_FRAPPE,
Self::CatppuccinMacchiato => {
&palette::EXTENDED_CATPPUCCIN_MACCHIATO
}
Self::CatppuccinMocha => &palette::EXTENDED_CATPPUCCIN_MOCHA,
Self::TokyoNight => &palette::EXTENDED_TOKYO_NIGHT,
Self::TokyoNightStorm => &palette::EXTENDED_TOKYO_NIGHT_STORM,
Self::TokyoNightLight => &palette::EXTENDED_TOKYO_NIGHT_LIGHT,
Self::KanagawaWave => &palette::EXTENDED_KANAGAWA_WAVE,
Self::KanagawaDragon => &palette::EXTENDED_KANAGAWA_DRAGON,
Self::KanagawaLotus => &palette::EXTENDED_KANAGAWA_LOTUS,
Self::Moonfly => &palette::EXTENDED_MOONFLY,
Self::Nightfly => &palette::EXTENDED_NIGHTFLY,
Self::Oxocarbon => &palette::EXTENDED_OXOCARBON,
Self::Ferra => &palette::EXTENDED_FERRA,
Self::Custom(custom) => &custom.extended,
}
}
}
impl fmt::Display for Theme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Custom {
name: Cow<'static, str>,
palette: Palette,
extended: palette::Extended,
}
impl Custom {
pub fn new(name: String, palette: Palette) -> Self {
Self::with_fn(name, palette, palette::Extended::generate)
}
pub fn with_fn(
name: impl Into<Cow<'static, str>>,
palette: Palette,
generate: impl FnOnce(Palette) -> palette::Extended,
) -> Self {
Self {
name: name.into(),
palette,
extended: generate(palette),
}
}
}
impl fmt::Display for Custom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Mode {
#[default]
None,
Light,
Dark,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Style {
pub background_color: Color,
pub text_color: Color,
}
pub trait Base {
fn default(preference: Mode) -> Self;
fn mode(&self) -> Mode;
fn base(&self) -> Style;
fn palette(&self) -> Option<Palette>;
fn name(&self) -> &str;
}
impl Base for Theme {
fn default(preference: Mode) -> Self {
use std::env;
use std::sync::OnceLock;
static SYSTEM: OnceLock<Option<Theme>> = OnceLock::new();
let system = SYSTEM.get_or_init(|| {
let name = env::var("ICED_THEME").ok()?;
Theme::ALL
.iter()
.find(|theme| theme.to_string() == name)
.cloned()
});
if let Some(system) = system {
return system.clone();
}
match preference {
Mode::None | Mode::Light => Self::Light,
Mode::Dark => Self::Dark,
}
}
fn mode(&self) -> Mode {
if self.extended_palette().is_dark {
Mode::Dark
} else {
Mode::Light
}
}
fn base(&self) -> Style {
default(self)
}
fn palette(&self) -> Option<Palette> {
Some(self.palette())
}
fn name(&self) -> &str {
match self {
Self::Light => "Light",
Self::Dark => "Dark",
Self::Dracula => "Dracula",
Self::Nord => "Nord",
Self::SolarizedLight => "Solarized Light",
Self::SolarizedDark => "Solarized Dark",
Self::GruvboxLight => "Gruvbox Light",
Self::GruvboxDark => "Gruvbox Dark",
Self::CatppuccinLatte => "Catppuccin Latte",
Self::CatppuccinFrappe => "Catppuccin Frappé",
Self::CatppuccinMacchiato => "Catppuccin Macchiato",
Self::CatppuccinMocha => "Catppuccin Mocha",
Self::TokyoNight => "Tokyo Night",
Self::TokyoNightStorm => "Tokyo Night Storm",
Self::TokyoNightLight => "Tokyo Night Light",
Self::KanagawaWave => "Kanagawa Wave",
Self::KanagawaDragon => "Kanagawa Dragon",
Self::KanagawaLotus => "Kanagawa Lotus",
Self::Moonfly => "Moonfly",
Self::Nightfly => "Nightfly",
Self::Oxocarbon => "Oxocarbon",
Self::Ferra => "Ferra",
Self::Custom(custom) => &custom.name,
}
}
}
pub fn default(theme: &Theme) -> Style {
let palette = theme.extended_palette();
Style {
background_color: palette.background.base.color,
text_color: palette.background.base.text,
}
}