1use std::str::FromStr;
2
3use ratatui::style::Color;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum ThemeVariant {
9 Default,
10 Framework,
11 Alucard,
12 CatppuccinFrappe,
13 CatppuccinLatte,
14 CatppuccinMacchiato,
15 CatppuccinMocha,
16 Dracula,
17 GameBoy,
18 GithubDark,
19 GithubLight,
20 GruvboxDark,
21 GruvboxLight,
22 MonochromeDark,
23 MonochromeLight,
24 MonokaiPro,
25}
26
27impl FromStr for ThemeVariant {
28 type Err = String;
29
30 fn from_str(s: &str) -> Result<Self, Self::Err> {
31 match s.to_lowercase().as_str() {
32 "default" => Ok(ThemeVariant::Default),
33 "framework" => Ok(ThemeVariant::Framework),
34 "alucard" => Ok(ThemeVariant::Alucard),
35 "catppuccin_frappe" => Ok(ThemeVariant::CatppuccinFrappe),
36 "catppuccin_latte" => Ok(ThemeVariant::CatppuccinLatte),
37 "catppuccin_macchiato" => Ok(ThemeVariant::CatppuccinMacchiato),
38 "catppuccin_mocha" => Ok(ThemeVariant::CatppuccinMocha),
39 "dracula" => Ok(ThemeVariant::Dracula),
40 "gameboy" => Ok(ThemeVariant::GameBoy),
41 "github_dark" => Ok(ThemeVariant::GithubDark),
42 "github_light" => Ok(ThemeVariant::GithubLight),
43 "gruvbox_dark" => Ok(ThemeVariant::GruvboxDark),
44 "gruvbox_light" => Ok(ThemeVariant::GruvboxLight),
45 "monochrome_dark" => Ok(ThemeVariant::MonochromeDark),
46 "monochrome_light" => Ok(ThemeVariant::MonochromeLight),
47 "monokai_pro" => Ok(ThemeVariant::MonokaiPro),
48 _ => Err(format!("Unknown theme: {}", s)),
49 }
50 }
51}
52
53impl ThemeVariant {
54 pub fn name(&self) -> &'static str {
55 match self {
56 ThemeVariant::Default => "Default",
57 ThemeVariant::Framework => "Framework",
58 ThemeVariant::Alucard => "Alucard",
59 ThemeVariant::CatppuccinFrappe => "Catppuccin Frappe",
60 ThemeVariant::CatppuccinLatte => "Catppuccin Latte",
61 ThemeVariant::CatppuccinMacchiato => "Catppuccin Macchiato",
62 ThemeVariant::CatppuccinMocha => "Catppuccin Mocha",
63 ThemeVariant::Dracula => "Dracula",
64 ThemeVariant::GameBoy => "Game Boy",
65 ThemeVariant::GithubDark => "GitHub Dark",
66 ThemeVariant::GithubLight => "GitHub Light",
67 ThemeVariant::GruvboxDark => "Gruvbox Dark",
68 ThemeVariant::GruvboxLight => "Gruvbox Light",
69 ThemeVariant::MonochromeDark => "Monochrome Dark",
70 ThemeVariant::MonochromeLight => "Monochrome Light",
71 ThemeVariant::MonokaiPro => "Monokai Pro",
72 }
73 }
74
75 pub const ALL: [ThemeVariant; 16] = [
76 ThemeVariant::Default,
77 ThemeVariant::Framework,
78 ThemeVariant::Alucard,
79 ThemeVariant::CatppuccinFrappe,
80 ThemeVariant::CatppuccinLatte,
81 ThemeVariant::CatppuccinMacchiato,
82 ThemeVariant::CatppuccinMocha,
83 ThemeVariant::Dracula,
84 ThemeVariant::GameBoy,
85 ThemeVariant::GithubDark,
86 ThemeVariant::GithubLight,
87 ThemeVariant::GruvboxDark,
88 ThemeVariant::GruvboxLight,
89 ThemeVariant::MonochromeDark,
90 ThemeVariant::MonochromeLight,
91 ThemeVariant::MonokaiPro,
92 ];
93
94 pub fn next(&self) -> Self {
95 let current_idx = Self::ALL.iter().position(|t| t == self).unwrap();
96 Self::ALL[(current_idx + 1) % Self::ALL.len()]
97 }
98
99 pub fn previous(&self) -> Self {
100 let current_idx = Self::ALL.iter().position(|t| t == self).unwrap();
101 let prev_idx = if current_idx == 0 {
102 Self::ALL.len() - 1
103 } else {
104 current_idx - 1
105 };
106 Self::ALL[prev_idx]
107 }
108}
109
110pub struct Theme {
111 pub variant: ThemeVariant,
112 pub text: Color,
113 pub background: Color,
114 pub border: Color,
115 pub border_active: Color,
116 pub indication_ok: Color,
117 pub indication_warning: Color,
118 pub brightness_bar: Color,
119 pub charge_bar: Color,
120 pub bar_background: Color,
121 pub highlighted_text: Color,
122 pub informative_text: Color,
123}
124
125impl Default for Theme {
126 fn default() -> Self {
127 Theme::from_variant(ThemeVariant::Default)
128 }
129}
130
131impl Theme {
132 pub fn from_variant(variant: ThemeVariant) -> Self {
133 match variant {
134 ThemeVariant::Default => Self::default0(),
135 ThemeVariant::Framework => Self::framework(),
136 ThemeVariant::Alucard => Self::alucard(),
137 ThemeVariant::CatppuccinFrappe => Self::catppuccin_frappe(),
138 ThemeVariant::CatppuccinLatte => Self::catppuccin_latte(),
139 ThemeVariant::CatppuccinMacchiato => Self::catppuccin_macchiato(),
140 ThemeVariant::CatppuccinMocha => Self::catppuccin_mocha(),
141 ThemeVariant::Dracula => Self::dracula(),
142 ThemeVariant::GameBoy => Self::gameboy(),
143 ThemeVariant::GithubDark => Self::github_dark(),
144 ThemeVariant::GithubLight => Self::github_light(),
145 ThemeVariant::GruvboxDark => Self::gruvbox_dark(),
146 ThemeVariant::GruvboxLight => Self::gruvbox_light(),
147 ThemeVariant::MonochromeDark => Self::monochrome_dark(),
148 ThemeVariant::MonochromeLight => Self::monochrome_light(),
149 ThemeVariant::MonokaiPro => Self::monokai_pro(),
150 }
151 }
152
153 pub fn default0() -> Self {
154 Self {
155 variant: ThemeVariant::Default,
156 text: Color::Indexed(7),
157 background: Color::Indexed(0),
158 border: Color::Indexed(15),
159 border_active: Color::Indexed(3),
160 indication_ok: Color::Indexed(2),
161 indication_warning: Color::Indexed(1),
162 brightness_bar: Color::Indexed(4),
163 charge_bar: Color::Indexed(4),
164 bar_background: Color::Indexed(0),
165 highlighted_text: Color::Indexed(4),
166 informative_text: Color::Indexed(5),
167 }
168 }
169
170 pub fn framework() -> Self {
171 Self {
172 variant: ThemeVariant::Framework,
173 text: Color::from_str("#F5F5F5").unwrap(),
174 background: Color::from_str("#1F1F1F").unwrap(),
175 border: Color::from_str("#F45A27").unwrap(),
176 border_active: Color::from_str("#FFD600").unwrap(),
177 indication_ok: Color::from_str("#00B16A").unwrap(),
178 indication_warning: Color::from_str("#E53935").unwrap(),
179 brightness_bar: Color::from_str("#fdbe54").unwrap(),
180 charge_bar: Color::from_str("#9481D8").unwrap(),
181 bar_background: Color::from_str("#363636").unwrap(),
182 highlighted_text: Color::from_str("#AEC2C9").unwrap(),
183 informative_text: Color::from_str("#9481D8").unwrap(),
184 }
185 }
186
187 pub fn alucard() -> Self {
188 Self {
189 variant: ThemeVariant::Alucard,
190 text: Color::from_str("#1F1F1F").unwrap(),
191 background: Color::from_str("#FFFBEB").unwrap(),
192 border: Color::from_str("#A34D14").unwrap(),
193 border_active: Color::from_str("#846E15").unwrap(),
194 indication_ok: Color::from_str("#14710A").unwrap(),
195 indication_warning: Color::from_str("#CB3A2A").unwrap(),
196 brightness_bar: Color::from_str("#846E15").unwrap(),
197 charge_bar: Color::from_str("#644AC9").unwrap(),
198 bar_background: Color::from_str("#CFCFDE").unwrap(),
199 highlighted_text: Color::from_str("#036A96").unwrap(),
200 informative_text: Color::from_str("#644AC9").unwrap(),
201 }
202 }
203
204 pub fn catppuccin_frappe() -> Self {
205 Self {
206 variant: ThemeVariant::CatppuccinFrappe,
207 text: Color::from_str("#C6D0F5").unwrap(),
208 background: Color::from_str("#232634").unwrap(),
209 border: Color::from_str("#EF9F76").unwrap(),
210 border_active: Color::from_str("#E5C890").unwrap(),
211 indication_ok: Color::from_str("#A6D189").unwrap(),
212 indication_warning: Color::from_str("#E78284").unwrap(),
213 brightness_bar: Color::from_str("#E5C890").unwrap(),
214 charge_bar: Color::from_str("#8CAAEE").unwrap(),
215 bar_background: Color::from_str("#303446").unwrap(),
216 highlighted_text: Color::from_str("#8caaee").unwrap(),
217 informative_text: Color::from_str("#CA9EE6").unwrap(),
218 }
219 }
220
221 pub fn catppuccin_latte() -> Self {
222 Self {
223 variant: ThemeVariant::CatppuccinLatte,
224 text: Color::from_str("#4C4F69").unwrap(),
225 background: Color::from_str("#DCE0E8").unwrap(),
226 border: Color::from_str("#D20F39").unwrap(),
227 border_active: Color::from_str("#DF8E1D").unwrap(),
228 indication_ok: Color::from_str("#40A02B").unwrap(),
229 indication_warning: Color::from_str("#D20F39").unwrap(),
230 brightness_bar: Color::from_str("#DF8E1D").unwrap(),
231 charge_bar: Color::from_str("#1E66F5").unwrap(),
232 bar_background: Color::from_str("#EFF1F5").unwrap(),
233 highlighted_text: Color::from_str("#1e66f5").unwrap(),
234 informative_text: Color::from_str("#8839EF").unwrap(),
235 }
236 }
237
238 pub fn catppuccin_macchiato() -> Self {
239 Self {
240 variant: ThemeVariant::CatppuccinMacchiato,
241 text: Color::from_str("#CAD3F5").unwrap(),
242 background: Color::from_str("#181926").unwrap(),
243 border: Color::from_str("#F5A97F").unwrap(),
244 border_active: Color::from_str("#EED49F").unwrap(),
245 indication_ok: Color::from_str("#A6DA95").unwrap(),
246 indication_warning: Color::from_str("#ED8796").unwrap(),
247 brightness_bar: Color::from_str("#EED49F").unwrap(),
248 charge_bar: Color::from_str("#8AADF4").unwrap(),
249 bar_background: Color::from_str("#24273A").unwrap(),
250 highlighted_text: Color::from_str("#8aadf4").unwrap(),
251 informative_text: Color::from_str("#C6A0F6").unwrap(),
252 }
253 }
254
255 pub fn catppuccin_mocha() -> Self {
256 Self {
257 variant: ThemeVariant::CatppuccinMocha,
258 text: Color::from_str("#CDD6F4").unwrap(),
259 background: Color::from_str("#11111B").unwrap(),
260 border: Color::from_str("#FAB387").unwrap(),
261 border_active: Color::from_str("#F9E2AF").unwrap(),
262 indication_ok: Color::from_str("#A6E3A1").unwrap(),
263 indication_warning: Color::from_str("#F38BA8").unwrap(),
264 brightness_bar: Color::from_str("#F9E2AF").unwrap(),
265 charge_bar: Color::from_str("#89B4FA").unwrap(),
266 bar_background: Color::from_str("#1E1E2E").unwrap(),
267 highlighted_text: Color::from_str("#89b4fa").unwrap(),
268 informative_text: Color::from_str("#CBA6f7").unwrap(),
269 }
270 }
271
272 pub fn dracula() -> Self {
273 Self {
274 variant: ThemeVariant::Dracula,
275 text: Color::from_str("#F8F8F2").unwrap(),
276 background: Color::from_str("#282A36").unwrap(),
277 border: Color::from_str("#FFB86C").unwrap(),
278 border_active: Color::from_str("#FFB86C").unwrap(),
279 indication_ok: Color::from_str("#50FA7B").unwrap(),
280 indication_warning: Color::from_str("#FF5555").unwrap(),
281 brightness_bar: Color::from_str("#F1FA8C").unwrap(),
282 charge_bar: Color::from_str("#8BE9FD").unwrap(),
283 bar_background: Color::from_str("#44475A").unwrap(),
284 highlighted_text: Color::from_str("#8BE9FD").unwrap(),
285 informative_text: Color::from_str("#BD93F9").unwrap(),
286 }
287 }
288
289 pub fn gameboy() -> Self {
290 Self {
291 variant: ThemeVariant::GameBoy,
292 text: Color::from_str("#9A9E3F").unwrap(),
293 background: Color::from_str("#1B2A09").unwrap(),
294 border: Color::from_str("#496B22").unwrap(),
295 border_active: Color::from_str("#9A9E3F").unwrap(),
296 indication_ok: Color::from_str("#9A9E3F").unwrap(),
297 indication_warning: Color::from_str("#9A9E3F").unwrap(),
298 brightness_bar: Color::from_str("#9A9E3F").unwrap(),
299 charge_bar: Color::from_str("#9A9E3F").unwrap(),
300 bar_background: Color::from_str("#0E450B").unwrap(),
301 highlighted_text: Color::from_str("#9A9E3F").unwrap(),
302 informative_text: Color::from_str("#9A9E3F").unwrap(),
303 }
304 }
305
306 pub fn github_dark() -> Self {
307 Self {
308 variant: ThemeVariant::GithubDark,
309 text: Color::from_str("#D1D7E0").unwrap(),
310 background: Color::from_str("#212830").unwrap(),
311 border: Color::from_str("#FF8E40").unwrap(),
312 border_active: Color::from_str("#D3FA37").unwrap(),
313 indication_ok: Color::from_str("#5fED83").unwrap(),
314 indication_warning: Color::from_str("#FF8E40").unwrap(),
315 brightness_bar: Color::from_str("#D3FA37").unwrap(),
316 charge_bar: Color::from_str("#1F6FEB").unwrap(),
317 bar_background: Color::from_str("#262C36").unwrap(),
318 highlighted_text: Color::from_str("#9EECFF").unwrap(),
319 informative_text: Color::from_str("#FF80D2").unwrap(),
320 }
321 }
322
323 pub fn github_light() -> Self {
324 Self {
325 variant: ThemeVariant::GithubLight,
326 text: Color::from_str("#000000").unwrap(),
327 background: Color::from_str("#FFFFFF").unwrap(),
328 border: Color::from_str("#703100").unwrap(),
329 border_active: Color::from_str("#DB9D00").unwrap(),
330 indication_ok: Color::from_str("#1f883D").unwrap(),
331 indication_warning: Color::from_str("#703100").unwrap(),
332 brightness_bar: Color::from_str("#DB9D00").unwrap(),
333 charge_bar: Color::from_str("#0969DA").unwrap(),
334 bar_background: Color::from_str("#F6F8FA").unwrap(),
335 highlighted_text: Color::from_str("#212183").unwrap(),
336 informative_text: Color::from_str("#8342FA").unwrap(),
337 }
338 }
339
340 pub fn gruvbox_dark() -> Self {
341 Self {
342 variant: ThemeVariant::GruvboxDark,
343 text: Color::from_str("#EBDBB2").unwrap(),
344 background: Color::from_str("#282828").unwrap(),
345 border: Color::from_str("#FE8019").unwrap(),
346 border_active: Color::from_str("#FABd2F").unwrap(),
347 indication_ok: Color::from_str("#B8BB26").unwrap(),
348 indication_warning: Color::from_str("#FE8019").unwrap(),
349 brightness_bar: Color::from_str("#FABD2F").unwrap(),
350 charge_bar: Color::from_str("#458588").unwrap(),
351 bar_background: Color::from_str("#504945").unwrap(),
352 highlighted_text: Color::from_str("#83A598").unwrap(),
353 informative_text: Color::from_str("#D3869B").unwrap(),
354 }
355 }
356
357 pub fn gruvbox_light() -> Self {
358 Self {
359 variant: ThemeVariant::GruvboxLight,
360 text: Color::from_str("#3C3836").unwrap(),
361 background: Color::from_str("#FFFFFF").unwrap(),
362 border: Color::from_str("#AF3A03").unwrap(),
363 border_active: Color::from_str("#D79921").unwrap(),
364 indication_ok: Color::from_str("#79740E").unwrap(),
365 indication_warning: Color::from_str("#AF3A03").unwrap(),
366 brightness_bar: Color::from_str("#B57614").unwrap(),
367 charge_bar: Color::from_str("#458588").unwrap(),
368 bar_background: Color::from_str("#D5C4A1").unwrap(),
369 highlighted_text: Color::from_str("#076678").unwrap(),
370 informative_text: Color::from_str("#8F3F71").unwrap(),
371 }
372 }
373
374 pub fn monochrome_dark() -> Self {
375 Self {
376 variant: ThemeVariant::MonochromeDark,
377 text: Color::from_str("#FFFFFF").unwrap(),
378 background: Color::from_str("#000000").unwrap(),
379 border: Color::from_str("#FFFFFF").unwrap(),
380 border_active: Color::from_str("#FFFFFF").unwrap(),
381 indication_ok: Color::from_str("#FFFFFF").unwrap(),
382 indication_warning: Color::from_str("#FFFFFF").unwrap(),
383 brightness_bar: Color::from_str("#FFFFFF").unwrap(),
384 charge_bar: Color::from_str("#FFFFFF").unwrap(),
385 bar_background: Color::from_str("#000000").unwrap(),
386 highlighted_text: Color::from_str("#FFFFFF").unwrap(),
387 informative_text: Color::from_str("#FFFFFF").unwrap(),
388 }
389 }
390
391 pub fn monochrome_light() -> Self {
392 Self {
393 variant: ThemeVariant::MonochromeLight,
394 text: Color::from_str("#000000").unwrap(),
395 background: Color::from_str("#FFFFFF").unwrap(),
396 border: Color::from_str("#000000").unwrap(),
397 border_active: Color::from_str("#000000").unwrap(),
398 indication_ok: Color::from_str("#000000").unwrap(),
399 indication_warning: Color::from_str("#000000").unwrap(),
400 brightness_bar: Color::from_str("#000000").unwrap(),
401 charge_bar: Color::from_str("#000000").unwrap(),
402 bar_background: Color::from_str("#FFFFFF").unwrap(),
403 highlighted_text: Color::from_str("#000000").unwrap(),
404 informative_text: Color::from_str("#000000").unwrap(),
405 }
406 }
407
408 pub fn monokai_pro() -> Self {
409 Self {
410 variant: ThemeVariant::MonokaiPro,
411 text: Color::from_str("#FFFFFF").unwrap(),
412 background: Color::from_str("#161517").unwrap(),
413 border: Color::from_str("#FC9867").unwrap(),
414 border_active: Color::from_str("#FFD866").unwrap(),
415 indication_ok: Color::from_str("#A9DC76").unwrap(),
416 indication_warning: Color::from_str("#FF6188").unwrap(),
417 brightness_bar: Color::from_str("#FFD866").unwrap(),
418 charge_bar: Color::from_str("#AB9DF2").unwrap(),
419 bar_background: Color::from_str("#373138").unwrap(),
420 highlighted_text: Color::from_str("#77DCE8").unwrap(),
421 informative_text: Color::from_str("#AB9DF2").unwrap(),
422 }
423 }
424}