1pub mod palette;
3
4pub use palette::Palette;
5
6use crate::Color;
7
8use std::borrow::Cow;
9use std::fmt;
10use std::sync::Arc;
11
12#[derive(Debug, Clone, PartialEq)]
14pub enum Theme {
15 Light,
17 Dark,
19 Dracula,
21 Nord,
23 SolarizedLight,
25 SolarizedDark,
27 GruvboxLight,
29 GruvboxDark,
31 CatppuccinLatte,
33 CatppuccinFrappe,
35 CatppuccinMacchiato,
37 CatppuccinMocha,
39 TokyoNight,
41 TokyoNightStorm,
43 TokyoNightLight,
45 KanagawaWave,
47 KanagawaDragon,
49 KanagawaLotus,
51 Moonfly,
53 Nightfly,
55 Oxocarbon,
57 Ferra,
59 Custom(Arc<Custom>),
61}
62
63impl Theme {
64 pub const ALL: &'static [Self] = &[
66 Self::Light,
67 Self::Dark,
68 Self::Dracula,
69 Self::Nord,
70 Self::SolarizedLight,
71 Self::SolarizedDark,
72 Self::GruvboxLight,
73 Self::GruvboxDark,
74 Self::CatppuccinLatte,
75 Self::CatppuccinFrappe,
76 Self::CatppuccinMacchiato,
77 Self::CatppuccinMocha,
78 Self::TokyoNight,
79 Self::TokyoNightStorm,
80 Self::TokyoNightLight,
81 Self::KanagawaWave,
82 Self::KanagawaDragon,
83 Self::KanagawaLotus,
84 Self::Moonfly,
85 Self::Nightfly,
86 Self::Oxocarbon,
87 Self::Ferra,
88 ];
89
90 pub fn custom(
92 name: impl Into<Cow<'static, str>>,
93 palette: Palette,
94 ) -> Self {
95 Self::custom_with_fn(name, palette, palette::Extended::generate)
96 }
97
98 pub fn custom_with_fn(
101 name: impl Into<Cow<'static, str>>,
102 palette: Palette,
103 generate: impl FnOnce(Palette) -> palette::Extended,
104 ) -> Self {
105 Self::Custom(Arc::new(Custom::with_fn(name, palette, generate)))
106 }
107
108 pub fn palette(&self) -> Palette {
110 match self {
111 Self::Light => Palette::LIGHT,
112 Self::Dark => Palette::DARK,
113 Self::Dracula => Palette::DRACULA,
114 Self::Nord => Palette::NORD,
115 Self::SolarizedLight => Palette::SOLARIZED_LIGHT,
116 Self::SolarizedDark => Palette::SOLARIZED_DARK,
117 Self::GruvboxLight => Palette::GRUVBOX_LIGHT,
118 Self::GruvboxDark => Palette::GRUVBOX_DARK,
119 Self::CatppuccinLatte => Palette::CATPPUCCIN_LATTE,
120 Self::CatppuccinFrappe => Palette::CATPPUCCIN_FRAPPE,
121 Self::CatppuccinMacchiato => Palette::CATPPUCCIN_MACCHIATO,
122 Self::CatppuccinMocha => Palette::CATPPUCCIN_MOCHA,
123 Self::TokyoNight => Palette::TOKYO_NIGHT,
124 Self::TokyoNightStorm => Palette::TOKYO_NIGHT_STORM,
125 Self::TokyoNightLight => Palette::TOKYO_NIGHT_LIGHT,
126 Self::KanagawaWave => Palette::KANAGAWA_WAVE,
127 Self::KanagawaDragon => Palette::KANAGAWA_DRAGON,
128 Self::KanagawaLotus => Palette::KANAGAWA_LOTUS,
129 Self::Moonfly => Palette::MOONFLY,
130 Self::Nightfly => Palette::NIGHTFLY,
131 Self::Oxocarbon => Palette::OXOCARBON,
132 Self::Ferra => Palette::FERRA,
133 Self::Custom(custom) => custom.palette,
134 }
135 }
136
137 pub fn extended_palette(&self) -> &palette::Extended {
139 match self {
140 Self::Light => &palette::EXTENDED_LIGHT,
141 Self::Dark => &palette::EXTENDED_DARK,
142 Self::Dracula => &palette::EXTENDED_DRACULA,
143 Self::Nord => &palette::EXTENDED_NORD,
144 Self::SolarizedLight => &palette::EXTENDED_SOLARIZED_LIGHT,
145 Self::SolarizedDark => &palette::EXTENDED_SOLARIZED_DARK,
146 Self::GruvboxLight => &palette::EXTENDED_GRUVBOX_LIGHT,
147 Self::GruvboxDark => &palette::EXTENDED_GRUVBOX_DARK,
148 Self::CatppuccinLatte => &palette::EXTENDED_CATPPUCCIN_LATTE,
149 Self::CatppuccinFrappe => &palette::EXTENDED_CATPPUCCIN_FRAPPE,
150 Self::CatppuccinMacchiato => {
151 &palette::EXTENDED_CATPPUCCIN_MACCHIATO
152 }
153 Self::CatppuccinMocha => &palette::EXTENDED_CATPPUCCIN_MOCHA,
154 Self::TokyoNight => &palette::EXTENDED_TOKYO_NIGHT,
155 Self::TokyoNightStorm => &palette::EXTENDED_TOKYO_NIGHT_STORM,
156 Self::TokyoNightLight => &palette::EXTENDED_TOKYO_NIGHT_LIGHT,
157 Self::KanagawaWave => &palette::EXTENDED_KANAGAWA_WAVE,
158 Self::KanagawaDragon => &palette::EXTENDED_KANAGAWA_DRAGON,
159 Self::KanagawaLotus => &palette::EXTENDED_KANAGAWA_LOTUS,
160 Self::Moonfly => &palette::EXTENDED_MOONFLY,
161 Self::Nightfly => &palette::EXTENDED_NIGHTFLY,
162 Self::Oxocarbon => &palette::EXTENDED_OXOCARBON,
163 Self::Ferra => &palette::EXTENDED_FERRA,
164 Self::Custom(custom) => &custom.extended,
165 }
166 }
167}
168
169impl fmt::Display for Theme {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 match self {
172 Self::Light => write!(f, "Light"),
173 Self::Dark => write!(f, "Dark"),
174 Self::Dracula => write!(f, "Dracula"),
175 Self::Nord => write!(f, "Nord"),
176 Self::SolarizedLight => write!(f, "Solarized Light"),
177 Self::SolarizedDark => write!(f, "Solarized Dark"),
178 Self::GruvboxLight => write!(f, "Gruvbox Light"),
179 Self::GruvboxDark => write!(f, "Gruvbox Dark"),
180 Self::CatppuccinLatte => write!(f, "Catppuccin Latte"),
181 Self::CatppuccinFrappe => write!(f, "Catppuccin Frappé"),
182 Self::CatppuccinMacchiato => write!(f, "Catppuccin Macchiato"),
183 Self::CatppuccinMocha => write!(f, "Catppuccin Mocha"),
184 Self::TokyoNight => write!(f, "Tokyo Night"),
185 Self::TokyoNightStorm => write!(f, "Tokyo Night Storm"),
186 Self::TokyoNightLight => write!(f, "Tokyo Night Light"),
187 Self::KanagawaWave => write!(f, "Kanagawa Wave"),
188 Self::KanagawaDragon => write!(f, "Kanagawa Dragon"),
189 Self::KanagawaLotus => write!(f, "Kanagawa Lotus"),
190 Self::Moonfly => write!(f, "Moonfly"),
191 Self::Nightfly => write!(f, "Nightfly"),
192 Self::Oxocarbon => write!(f, "Oxocarbon"),
193 Self::Ferra => write!(f, "Ferra"),
194 Self::Custom(custom) => custom.fmt(f),
195 }
196 }
197}
198
199#[derive(Debug, Clone, PartialEq)]
201pub struct Custom {
202 name: Cow<'static, str>,
203 palette: Palette,
204 extended: palette::Extended,
205}
206
207impl Custom {
208 pub fn new(name: String, palette: Palette) -> Self {
210 Self::with_fn(name, palette, palette::Extended::generate)
211 }
212
213 pub fn with_fn(
216 name: impl Into<Cow<'static, str>>,
217 palette: Palette,
218 generate: impl FnOnce(Palette) -> palette::Extended,
219 ) -> Self {
220 Self {
221 name: name.into(),
222 palette,
223 extended: generate(palette),
224 }
225 }
226}
227
228impl fmt::Display for Custom {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 write!(f, "{}", self.name)
231 }
232}
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
236pub enum Mode {
237 #[default]
239 None,
240 Light,
242 Dark,
244}
245
246#[derive(Debug, Clone, Copy, PartialEq)]
248pub struct Style {
249 pub background_color: Color,
251
252 pub text_color: Color,
254}
255
256pub trait Base {
258 fn default(preference: Mode) -> Self;
260
261 fn mode(&self) -> Mode;
263
264 fn base(&self) -> Style;
266
267 fn palette(&self) -> Option<Palette>;
273}
274
275impl Base for Theme {
276 fn default(preference: Mode) -> Self {
277 use std::env;
278 use std::sync::OnceLock;
279
280 static SYSTEM: OnceLock<Option<Theme>> = OnceLock::new();
281
282 let system = SYSTEM.get_or_init(|| {
283 let name = env::var("ICED_THEME").ok()?;
284
285 Theme::ALL
286 .iter()
287 .find(|theme| theme.to_string() == name)
288 .cloned()
289 });
290
291 if let Some(system) = system {
292 return system.clone();
293 }
294
295 match preference {
296 Mode::None | Mode::Light => Self::Light,
297 Mode::Dark => Self::Dark,
298 }
299 }
300
301 fn mode(&self) -> Mode {
302 if self.extended_palette().is_dark {
303 Mode::Dark
304 } else {
305 Mode::Light
306 }
307 }
308
309 fn base(&self) -> Style {
310 default(self)
311 }
312
313 fn palette(&self) -> Option<Palette> {
314 Some(self.palette())
315 }
316}
317
318pub fn default(theme: &Theme) -> Style {
320 let palette = theme.extended_palette();
321
322 Style {
323 background_color: palette.background.base.color,
324 text_color: palette.background.base.text,
325 }
326}