1use anstyle::RgbColor;
2use catppuccin::PALETTE;
3use hashbrown::HashMap;
4use once_cell::sync::Lazy;
5
6use crate::theme::types::{ThemeDefinition, ThemePalette, ThemeSuite};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
9enum CatppuccinFlavorKind {
10 Latte,
11 Frappe,
12 Macchiato,
13 Mocha,
14}
15
16impl CatppuccinFlavorKind {
17 const fn id(self) -> &'static str {
18 match self {
19 Self::Latte => "catppuccin-latte",
20 Self::Frappe => "catppuccin-frappe",
21 Self::Macchiato => "catppuccin-macchiato",
22 Self::Mocha => "catppuccin-mocha",
23 }
24 }
25
26 const fn label(self) -> &'static str {
27 match self {
28 Self::Latte => "Catppuccin Latte",
29 Self::Frappe => "Catppuccin Frappé",
30 Self::Macchiato => "Catppuccin Macchiato",
31 Self::Mocha => "Catppuccin Mocha",
32 }
33 }
34
35 fn flavor(self) -> catppuccin::Flavor {
36 match self {
37 Self::Latte => PALETTE.latte,
38 Self::Frappe => PALETTE.frappe,
39 Self::Macchiato => PALETTE.macchiato,
40 Self::Mocha => PALETTE.mocha,
41 }
42 }
43}
44
45static CATPPUCCIN_FLAVORS: &[CatppuccinFlavorKind] = &[
46 CatppuccinFlavorKind::Latte,
47 CatppuccinFlavorKind::Frappe,
48 CatppuccinFlavorKind::Macchiato,
49 CatppuccinFlavorKind::Mocha,
50];
51
52static REGISTRY: Lazy<HashMap<&'static str, ThemeDefinition>> = Lazy::new(|| {
53 let mut map = HashMap::new();
54 map.insert(
55 "ciapre-dark",
56 ThemeDefinition {
57 id: "ciapre-dark",
58 label: "Ciapre Dark",
59 palette: ThemePalette {
60 primary_accent: RgbColor(0xBF, 0xB3, 0x8F),
61 background: RgbColor(0x26, 0x26, 0x26),
62 foreground: RgbColor(0xBF, 0xB3, 0x8F),
63 secondary_accent: RgbColor(0xD9, 0x9A, 0x4E),
64 alert: RgbColor(0xFF, 0x8A, 0x8A),
65 logo_accent: RgbColor(0xD9, 0x9A, 0x4E),
66 },
67 },
68 );
69 map.insert(
70 "ciapre-blue",
71 ThemeDefinition {
72 id: "ciapre-blue",
73 label: "Ciapre Blue",
74 palette: ThemePalette {
75 primary_accent: RgbColor(0xBF, 0xB3, 0x8F),
76 background: RgbColor(0x17, 0x1C, 0x26),
77 foreground: RgbColor(0xBF, 0xB3, 0x8F),
78 secondary_accent: RgbColor(0xBF, 0xB3, 0x8F),
79 alert: RgbColor(0xFF, 0x8A, 0x8A),
80 logo_accent: RgbColor(0xD9, 0x9A, 0x4E),
81 },
82 },
83 );
84 map.insert(
85 "ciapre",
86 ThemeDefinition {
87 id: "ciapre",
88 label: "Ciapre",
89 palette: ThemePalette {
90 primary_accent: RgbColor(0xAE, 0xA4, 0x7F),
91 background: RgbColor(0x18, 0x18, 0x18),
92 foreground: RgbColor(0xAE, 0xA4, 0x7F),
93 secondary_accent: RgbColor(0xCC, 0x8A, 0x3E),
94 alert: RgbColor(0xC1, 0x6A, 0x68),
95 logo_accent: RgbColor(0xCC, 0x8A, 0x3E),
96 },
97 },
98 );
99 map.insert(
100 "solarized-dark",
101 ThemeDefinition {
102 id: "solarized-dark",
103 label: "Solarized Dark",
104 palette: ThemePalette {
105 primary_accent: RgbColor(0x83, 0x94, 0x96),
106 background: RgbColor(0x00, 0x2B, 0x36),
107 foreground: RgbColor(0x83, 0x94, 0x96),
108 secondary_accent: RgbColor(0x3A, 0x95, 0xD6),
109 alert: RgbColor(0xE5, 0x67, 0x65),
110 logo_accent: RgbColor(0x8B, 0x69, 0x00),
111 },
112 },
113 );
114 map.insert(
115 "solarized-light",
116 ThemeDefinition {
117 id: "solarized-light",
118 label: "Solarized Light",
119 palette: ThemePalette {
120 primary_accent: RgbColor(0x58, 0x6E, 0x75),
121 background: RgbColor(0xFD, 0xF6, 0xE3),
122 foreground: RgbColor(0x58, 0x6E, 0x75),
123 secondary_accent: RgbColor(0x20, 0x73, 0xAE),
124 alert: RgbColor(0xD3, 0x30, 0x2D),
125 logo_accent: RgbColor(0x8B, 0x69, 0x00),
126 },
127 },
128 );
129 map.insert(
130 "solarized-dark-hc",
131 ThemeDefinition {
132 id: "solarized-dark-hc",
133 label: "Solarized Dark Higher Contrast",
134 palette: ThemePalette {
135 primary_accent: RgbColor(0x83, 0x94, 0x96),
136 background: RgbColor(0x00, 0x28, 0x31),
137 foreground: RgbColor(0xE9, 0xE3, 0xCC),
138 secondary_accent: RgbColor(0x4A, 0x90, 0xD2),
139 alert: RgbColor(0xE0, 0x65, 0x6A),
140 logo_accent: RgbColor(0xAF, 0x86, 0x21),
141 },
142 },
143 );
144 map.insert(
145 "gruvbox-dark",
146 ThemeDefinition {
147 id: "gruvbox-dark",
148 label: "Gruvbox Dark",
149 palette: ThemePalette {
150 primary_accent: RgbColor(0xA8, 0x99, 0x84),
151 background: RgbColor(0x28, 0x28, 0x28),
152 foreground: RgbColor(0xA8, 0x99, 0x84),
153 secondary_accent: RgbColor(0x63, 0x99, 0x9B),
154 alert: RgbColor(0xDE, 0x71, 0x6C),
155 logo_accent: RgbColor(0xD7, 0x99, 0x21),
156 },
157 },
158 );
159 map.insert(
160 "gruvbox-dark-hard",
161 ThemeDefinition {
162 id: "gruvbox-dark-hard",
163 label: "Gruvbox Dark Hard",
164 palette: ThemePalette {
165 primary_accent: RgbColor(0xA8, 0x99, 0x84),
166 background: RgbColor(0x1D, 0x20, 0x21),
167 foreground: RgbColor(0xA8, 0x99, 0x84),
168 secondary_accent: RgbColor(0x58, 0x91, 0x94),
169 alert: RgbColor(0xDB, 0x64, 0x5F),
170 logo_accent: RgbColor(0xD7, 0x99, 0x21),
171 },
172 },
173 );
174 map.insert(
175 "gruvbox-light",
176 ThemeDefinition {
177 id: "gruvbox-light",
178 label: "Gruvbox Light",
179 palette: ThemePalette {
180 primary_accent: RgbColor(0x78, 0x6C, 0x61),
181 background: RgbColor(0xFB, 0xF4, 0xE8),
182 foreground: RgbColor(0x78, 0x6C, 0x61),
183 secondary_accent: RgbColor(0x3E, 0x78, 0x7A),
184 alert: RgbColor(0x9D, 0x00, 0x06),
185 logo_accent: RgbColor(0x98, 0x63, 0x11),
186 },
187 },
188 );
189 map.insert(
190 "gruvbox-light-hard",
191 ThemeDefinition {
192 id: "gruvbox-light-hard",
193 label: "Gruvbox Light Hard",
194 palette: ThemePalette {
195 primary_accent: RgbColor(0x50, 0x49, 0x45),
196 background: RgbColor(0xF9, 0xF5, 0xD7),
197 foreground: RgbColor(0x50, 0x49, 0x45),
198 secondary_accent: RgbColor(0x3D, 0x76, 0x79),
199 alert: RgbColor(0x9D, 0x00, 0x06),
200 logo_accent: RgbColor(0x98, 0x63, 0x11),
201 },
202 },
203 );
204 map.insert(
205 "gruvbox-material",
206 ThemeDefinition {
207 id: "gruvbox-material",
208 label: "Gruvbox Material",
209 palette: ThemePalette {
210 primary_accent: RgbColor(0xD4, 0xBE, 0x98),
211 background: RgbColor(0x28, 0x2E, 0x33),
212 foreground: RgbColor(0xD4, 0xBE, 0x98),
213 secondary_accent: RgbColor(0x89, 0xB4, 0x82),
214 alert: RgbColor(0xEB, 0x70, 0x6A),
215 logo_accent: RgbColor(0xE7, 0xA7, 0x2F),
216 },
217 },
218 );
219 map.insert(
220 "gruvbox-material-dark",
221 ThemeDefinition {
222 id: "gruvbox-material-dark",
223 label: "Gruvbox Material Dark",
224 palette: ThemePalette {
225 primary_accent: RgbColor(0xD4, 0xBE, 0x98),
226 background: RgbColor(0x28, 0x2E, 0x33),
227 foreground: RgbColor(0xD4, 0xBE, 0x98),
228 secondary_accent: RgbColor(0x89, 0xB4, 0x82),
229 alert: RgbColor(0xEB, 0x70, 0x6A),
230 logo_accent: RgbColor(0xE7, 0xA7, 0x2F),
231 },
232 },
233 );
234 map.insert(
235 "gruvbox-material-light",
236 ThemeDefinition {
237 id: "gruvbox-material-light",
238 label: "Gruvbox Material Light",
239 palette: ThemePalette {
240 primary_accent: RgbColor(0x65, 0x49, 0x31),
241 background: RgbColor(0xFB, 0xF1, 0xC7),
242 foreground: RgbColor(0x65, 0x49, 0x31),
243 secondary_accent: RgbColor(0x49, 0x75, 0x59),
244 alert: RgbColor(0xB7, 0x46, 0x46),
245 logo_accent: RgbColor(0x97, 0x5F, 0x08),
246 },
247 },
248 );
249 map.insert(
250 "ayu",
251 ThemeDefinition {
252 id: "ayu",
253 label: "Ayu Dark",
254 palette: ThemePalette {
255 primary_accent: RgbColor(0xE6, 0xE1, 0xCF),
256 background: RgbColor(0x0F, 0x14, 0x19),
257 foreground: RgbColor(0xE6, 0xE1, 0xCF),
258 secondary_accent: RgbColor(0x39, 0xBA, 0xE6),
259 alert: RgbColor(0xFF, 0x33, 0x33),
260 logo_accent: RgbColor(0xE6, 0xB4, 0x50),
261 },
262 },
263 );
264 map.insert(
265 "ayu-mirage",
266 ThemeDefinition {
267 id: "ayu-mirage",
268 label: "Ayu Mirage",
269 palette: ThemePalette {
270 primary_accent: RgbColor(0xCB, 0xCC, 0xCC),
271 background: RgbColor(0x1F, 0x24, 0x2D),
272 foreground: RgbColor(0xCB, 0xCC, 0xCC),
273 secondary_accent: RgbColor(0x5C, 0xC5, 0xFF),
274 alert: RgbColor(0xFF, 0x66, 0x66),
275 logo_accent: RgbColor(0xFF, 0xCC, 0x66),
276 },
277 },
278 );
279 map.insert(
280 "dracula",
281 ThemeDefinition {
282 id: "dracula",
283 label: "Dracula",
284 palette: ThemePalette {
285 primary_accent: RgbColor(0xF8, 0xF8, 0xF2),
286 background: RgbColor(0x28, 0x2A, 0x36),
287 foreground: RgbColor(0xF8, 0xF8, 0xF2),
288 secondary_accent: RgbColor(0x8B, 0xE9, 0xFD),
289 alert: RgbColor(0xFF, 0x58, 0x58),
290 logo_accent: RgbColor(0xFF, 0xB8, 0x6C),
291 },
292 },
293 );
294 map.insert(
295 "github-dark",
296 ThemeDefinition {
297 id: "github-dark",
298 label: "GitHub Dark",
299 palette: ThemePalette {
300 primary_accent: RgbColor(0xC9, 0xD1, 0xD9),
301 background: RgbColor(0x0D, 0x11, 0x17),
302 foreground: RgbColor(0xC9, 0xD1, 0xD9),
303 secondary_accent: RgbColor(0x58, 0xA6, 0xFF),
304 alert: RgbColor(0xF8, 0x51, 0x49),
305 logo_accent: RgbColor(0xD2, 0x99, 0x22),
306 },
307 },
308 );
309 map.insert(
310 "github",
311 ThemeDefinition {
312 id: "github",
313 label: "GitHub Light",
314 palette: ThemePalette {
315 primary_accent: RgbColor(0x24, 0x29, 0x2E),
316 background: RgbColor(0xFF, 0xFF, 0xFF),
317 foreground: RgbColor(0x24, 0x29, 0x2E),
318 secondary_accent: RgbColor(0x03, 0x66, 0xD6),
319 alert: RgbColor(0xD5, 0x39, 0x48),
320 logo_accent: RgbColor(0x90, 0x70, 0x00),
321 },
322 },
323 );
324 map.insert(
325 "atom-one-dark",
326 ThemeDefinition {
327 id: "atom-one-dark",
328 label: "Atom One Dark",
329 palette: ThemePalette {
330 primary_accent: RgbColor(0xAB, 0xB2, 0xBF),
331 background: RgbColor(0x28, 0x2C, 0x34),
332 foreground: RgbColor(0xAB, 0xB2, 0xBF),
333 secondary_accent: RgbColor(0x61, 0xAF, 0xEF),
334 alert: RgbColor(0xE2, 0x73, 0x7C),
335 logo_accent: RgbColor(0xE5, 0xC0, 0x7B),
336 },
337 },
338 );
339 map.insert(
340 "atom-one-light",
341 ThemeDefinition {
342 id: "atom-one-light",
343 label: "Atom One Light",
344 palette: ThemePalette {
345 primary_accent: RgbColor(0x38, 0x3A, 0x42),
346 background: RgbColor(0xFA, 0xFA, 0xFA),
347 foreground: RgbColor(0x38, 0x3A, 0x42),
348 secondary_accent: RgbColor(0x3E, 0x70, 0xC3),
349 alert: RgbColor(0xC2, 0x49, 0x3E),
350 logo_accent: RgbColor(0x98, 0x62, 0x00),
351 },
352 },
353 );
354 map.insert(
355 "tomorrow",
356 ThemeDefinition {
357 id: "tomorrow",
358 label: "Tomorrow",
359 palette: ThemePalette {
360 primary_accent: RgbColor(0x4D, 0x4D, 0x4C),
361 background: RgbColor(0xFF, 0xFF, 0xFF),
362 foreground: RgbColor(0x4D, 0x4D, 0x4C),
363 secondary_accent: RgbColor(0x41, 0x7A, 0xA2),
364 alert: RgbColor(0xC8, 0x28, 0x29),
365 logo_accent: RgbColor(0x99, 0x6C, 0x03),
366 },
367 },
368 );
369 map.insert(
370 "tomorrow-night",
371 ThemeDefinition {
372 id: "tomorrow-night",
373 label: "Tomorrow Night",
374 palette: ThemePalette {
375 primary_accent: RgbColor(0xC5, 0xC8, 0xC6),
376 background: RgbColor(0x1D, 0x1F, 0x21),
377 foreground: RgbColor(0xC5, 0xC8, 0xC6),
378 secondary_accent: RgbColor(0x81, 0xA2, 0xBE),
379 alert: RgbColor(0xCE, 0x6B, 0x6B),
380 logo_accent: RgbColor(0xDE, 0x93, 0x5F),
381 },
382 },
383 );
384 map.insert(
385 "tomorrow-night-blue",
386 ThemeDefinition {
387 id: "tomorrow-night-blue",
388 label: "Tomorrow Night Blue",
389 palette: ThemePalette {
390 primary_accent: RgbColor(0xFF, 0xFF, 0xFF),
391 background: RgbColor(0x00, 0x2E, 0x4E),
392 foreground: RgbColor(0xFF, 0xFF, 0xFF),
393 secondary_accent: RgbColor(0x7A, 0xBD, 0xFF),
394 alert: RgbColor(0xFF, 0x9D, 0x9D),
395 logo_accent: RgbColor(0xFF, 0xC8, 0x80),
396 },
397 },
398 );
399 map.insert(
400 "tomorrow-night-bright",
401 ThemeDefinition {
402 id: "tomorrow-night-bright",
403 label: "Tomorrow Night Bright",
404 palette: ThemePalette {
405 primary_accent: RgbColor(0xDE, 0xDE, 0xDE),
406 background: RgbColor(0x00, 0x00, 0x00),
407 foreground: RgbColor(0xDE, 0xDE, 0xDE),
408 secondary_accent: RgbColor(0x7A, 0xBD, 0xFF),
409 alert: RgbColor(0xFF, 0x87, 0x87),
410 logo_accent: RgbColor(0xFF, 0xC8, 0x80),
411 },
412 },
413 );
414 map.insert(
415 "tomorrow-night-eighties",
416 ThemeDefinition {
417 id: "tomorrow-night-eighties",
418 label: "Tomorrow Night Eighties",
419 palette: ThemePalette {
420 primary_accent: RgbColor(0xCC, 0xCC, 0xCC),
421 background: RgbColor(0x2D, 0x2D, 0x2D),
422 foreground: RgbColor(0xCC, 0xCC, 0xCC),
423 secondary_accent: RgbColor(0x68, 0x9A, 0xCD),
424 alert: RgbColor(0xF2, 0x77, 0x7A),
425 logo_accent: RgbColor(0xF9, 0x91, 0x57),
426 },
427 },
428 );
429 map.insert(
430 "tomorrow-night-burns",
431 ThemeDefinition {
432 id: "tomorrow-night-burns",
433 label: "Tomorrow Night Burns",
434 palette: ThemePalette {
435 primary_accent: RgbColor(0xD0, 0xD0, 0xD0),
436 background: RgbColor(0x15, 0x12, 0x0E),
437 foreground: RgbColor(0xD0, 0xD0, 0xD0),
438 secondary_accent: RgbColor(0x6C, 0x99, 0xB4),
439 alert: RgbColor(0xC0, 0x63, 0x63),
440 logo_accent: RgbColor(0xC4, 0x8D, 0x53),
441 },
442 },
443 );
444 map.insert(
445 "material-ocean",
446 ThemeDefinition {
447 id: "material-ocean",
448 label: "Material Ocean",
449 palette: ThemePalette {
450 primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
451 background: RgbColor(0x0F, 0x11, 0x1A),
452 foreground: RgbColor(0xEE, 0xEE, 0xEE),
453 secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
454 alert: RgbColor(0xF0, 0x72, 0x79),
455 logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
456 },
457 },
458 );
459 map.insert(
460 "material-dark",
461 ThemeDefinition {
462 id: "material-dark",
463 label: "Material Dark",
464 palette: ThemePalette {
465 primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
466 background: RgbColor(0x26, 0x32, 0x38),
467 foreground: RgbColor(0xEE, 0xEE, 0xEE),
468 secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
469 alert: RgbColor(0xF0, 0x72, 0x79),
470 logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
471 },
472 },
473 );
474 map.insert(
475 "material",
476 ThemeDefinition {
477 id: "material",
478 label: "Material",
479 palette: ThemePalette {
480 primary_accent: RgbColor(0xEE, 0xEE, 0xEE),
481 background: RgbColor(0x26, 0x32, 0x38),
482 foreground: RgbColor(0xEE, 0xEE, 0xEE),
483 secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
484 alert: RgbColor(0xF0, 0x72, 0x79),
485 logo_accent: RgbColor(0xFF, 0xCB, 0x6B),
486 },
487 },
488 );
489 map.insert(
490 "monokai-classic",
491 ThemeDefinition {
492 id: "monokai-classic",
493 label: "Monokai Classic",
494 palette: ThemePalette {
495 primary_accent: RgbColor(0xF8, 0xF8, 0xF2),
496 background: RgbColor(0x27, 0x28, 0x22),
497 foreground: RgbColor(0xF8, 0xF8, 0xF2),
498 secondary_accent: RgbColor(0x66, 0xD9, 0xEF),
499 alert: RgbColor(0xFA, 0x4F, 0x8D),
500 logo_accent: RgbColor(0xFD, 0x97, 0x1F),
501 },
502 },
503 );
504 map.insert(
505 "night-owl",
506 ThemeDefinition {
507 id: "night-owl",
508 label: "Night Owl",
509 palette: ThemePalette {
510 primary_accent: RgbColor(0xD6, 0xDE, 0xEB),
511 background: RgbColor(0x01, 0x17, 0x27),
512 foreground: RgbColor(0xD6, 0xDE, 0xEB),
513 secondary_accent: RgbColor(0x82, 0xAA, 0xFF),
514 alert: RgbColor(0xEF, 0x53, 0x50),
515 logo_accent: RgbColor(0xFA, 0xC8, 0x63),
516 },
517 },
518 );
519 map.insert(
520 "zenburn",
521 ThemeDefinition {
522 id: "zenburn",
523 label: "Zenburn",
524 palette: ThemePalette {
525 primary_accent: RgbColor(0xDC, 0xDC, 0xCC),
526 background: RgbColor(0x3F, 0x3F, 0x3F),
527 foreground: RgbColor(0xDC, 0xDC, 0xCC),
528 secondary_accent: RgbColor(0x9B, 0xB3, 0x8E),
529 alert: RgbColor(0xD2, 0x9F, 0x9F),
530 logo_accent: RgbColor(0xDF, 0xAF, 0x8F),
531 },
532 },
533 );
534 map.insert(
535 "jetbrains-darcula",
536 ThemeDefinition {
537 id: "jetbrains-darcula",
538 label: "JetBrains Darcula",
539 palette: ThemePalette {
540 primary_accent: RgbColor(0xA9, 0xB7, 0xC6),
541 background: RgbColor(0x2B, 0x2B, 0x2B),
542 foreground: RgbColor(0xA9, 0xB7, 0xC6),
543 secondary_accent: RgbColor(0x77, 0x97, 0xBC),
544 alert: RgbColor(0xCE, 0x7D, 0x7B),
545 logo_accent: RgbColor(0xBB, 0xA2, 0x6C),
546 },
547 },
548 );
549 map.insert(
550 "spacegray",
551 ThemeDefinition {
552 id: "spacegray",
553 label: "Spacegray",
554 palette: ThemePalette {
555 primary_accent: RgbColor(0xBD, 0xC3, 0xCE),
556 background: RgbColor(0x20, 0x22, 0x2B),
557 foreground: RgbColor(0xBD, 0xC3, 0xCE),
558 secondary_accent: RgbColor(0x7F, 0xA0, 0xC0),
559 alert: RgbColor(0xB8, 0x7A, 0x7A),
560 logo_accent: RgbColor(0xC0, 0x99, 0x70),
561 },
562 },
563 );
564 map.insert(
565 "spacegray-bright",
566 ThemeDefinition {
567 id: "spacegray-bright",
568 label: "Spacegray Bright",
569 palette: ThemePalette {
570 primary_accent: RgbColor(0xF2, 0xF2, 0xF2),
571 background: RgbColor(0x1A, 0x1A, 0x1A),
572 foreground: RgbColor(0xF2, 0xF2, 0xF2),
573 secondary_accent: RgbColor(0x88, 0xB0, 0xD0),
574 alert: RgbColor(0xD0, 0x70, 0x70),
575 logo_accent: RgbColor(0xD0, 0xA0, 0x60),
576 },
577 },
578 );
579 map.insert(
580 "spacegray-eighties",
581 ThemeDefinition {
582 id: "spacegray-eighties",
583 label: "Spacegray Eighties",
584 palette: ThemePalette {
585 primary_accent: RgbColor(0xEC, 0xEC, 0xEC),
586 background: RgbColor(0x22, 0x22, 0x2B),
587 foreground: RgbColor(0xEC, 0xEC, 0xEC),
588 secondary_accent: RgbColor(0x7A, 0x9F, 0xC2),
589 alert: RgbColor(0xCA, 0x72, 0x72),
590 logo_accent: RgbColor(0xC2, 0x95, 0x62),
591 },
592 },
593 );
594 map.insert(
595 "spacegray-eighties-dull",
596 ThemeDefinition {
597 id: "spacegray-eighties-dull",
598 label: "Spacegray Eighties Dull",
599 palette: ThemePalette {
600 primary_accent: RgbColor(0xC2, 0xC8, 0xD0),
601 background: RgbColor(0x2D, 0x30, 0x3A),
602 foreground: RgbColor(0xC2, 0xC8, 0xD0),
603 secondary_accent: RgbColor(0x7F, 0x9C, 0xB9),
604 alert: RgbColor(0xC2, 0x8C, 0x8C),
605 logo_accent: RgbColor(0xB5, 0x93, 0x6A),
606 },
607 },
608 );
609 map.insert(
610 "apple-classic",
611 ThemeDefinition {
612 id: "apple-classic",
613 label: "Apple Classic",
614 palette: ThemePalette {
615 primary_accent: RgbColor(0x00, 0x00, 0x00),
616 background: RgbColor(0xF6, 0xF4, 0xEC),
617 foreground: RgbColor(0x00, 0x00, 0x00),
618 secondary_accent: RgbColor(0x00, 0x66, 0x99),
619 alert: RgbColor(0xB0, 0x00, 0x00),
620 logo_accent: RgbColor(0x85, 0x6B, 0x00),
621 },
622 },
623 );
624 map.insert(
625 "apple-system-colors",
626 ThemeDefinition {
627 id: "apple-system-colors",
628 label: "Apple System Colors",
629 palette: ThemePalette {
630 primary_accent: RgbColor(0xF5, 0xF5, 0xF7),
631 background: RgbColor(0x1C, 0x1C, 0x1E),
632 foreground: RgbColor(0xF5, 0xF5, 0xF7),
633 secondary_accent: RgbColor(0x08, 0x6E, 0xD4),
634 alert: RgbColor(0xFF, 0x45, 0x3A),
635 logo_accent: RgbColor(0xFF, 0x9F, 0x0A),
636 },
637 },
638 );
639 map.insert(
640 "apple-system-colors-light",
641 ThemeDefinition {
642 id: "apple-system-colors-light",
643 label: "Apple System Colors Light",
644 palette: ThemePalette {
645 primary_accent: RgbColor(0x1C, 0x1C, 0x1E),
646 background: RgbColor(0xF5, 0xF5, 0xF7),
647 foreground: RgbColor(0x1C, 0x1C, 0x1E),
648 secondary_accent: RgbColor(0x08, 0x6E, 0xD4),
649 alert: RgbColor(0xD1, 0x30, 0x27),
650 logo_accent: RgbColor(0xA1, 0x5E, 0x00),
651 },
652 },
653 );
654 map.insert(
655 "vitesse-black",
656 ThemeDefinition {
657 id: "vitesse-black",
658 label: "Vitesse Black",
659 palette: ThemePalette {
660 primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
661 background: RgbColor(0x12, 0x12, 0x12),
662 foreground: RgbColor(0xDB, 0xD7, 0xCA),
663 secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
664 alert: RgbColor(0xB3, 0x6A, 0x6A),
665 logo_accent: RgbColor(0xFF, 0xA6, 0x57),
666 },
667 },
668 );
669 map.insert(
670 "vitesse-dark",
671 ThemeDefinition {
672 id: "vitesse-dark",
673 label: "Vitesse Dark",
674 palette: ThemePalette {
675 primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
676 background: RgbColor(0x18, 0x18, 0x18),
677 foreground: RgbColor(0xDB, 0xD7, 0xCA),
678 secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
679 alert: RgbColor(0xB6, 0x6F, 0x6F),
680 logo_accent: RgbColor(0xFF, 0xA6, 0x57),
681 },
682 },
683 );
684 map.insert(
685 "vitesse-dark-soft",
686 ThemeDefinition {
687 id: "vitesse-dark-soft",
688 label: "Vitesse Dark Soft",
689 palette: ThemePalette {
690 primary_accent: RgbColor(0xDB, 0xD7, 0xCA),
691 background: RgbColor(0x20, 0x1F, 0x1F),
692 foreground: RgbColor(0xDB, 0xD7, 0xCA),
693 secondary_accent: RgbColor(0x4D, 0x93, 0x8F),
694 alert: RgbColor(0xBA, 0x77, 0x77),
695 logo_accent: RgbColor(0xFF, 0xA6, 0x57),
696 },
697 },
698 );
699 map.insert(
700 "vitesse-light",
701 ThemeDefinition {
702 id: "vitesse-light",
703 label: "Vitesse Light",
704 palette: ThemePalette {
705 primary_accent: RgbColor(0x39, 0x3A, 0x34),
706 background: RgbColor(0xF6, 0xF1, 0xE5),
707 foreground: RgbColor(0x39, 0x3A, 0x34),
708 secondary_accent: RgbColor(0x1C, 0x6B, 0x48),
709 alert: RgbColor(0xA4, 0x55, 0x55),
710 logo_accent: RgbColor(0x97, 0x60, 0x00),
711 },
712 },
713 );
714 map.insert(
715 "vitesse-light-soft",
716 ThemeDefinition {
717 id: "vitesse-light-soft",
718 label: "Vitesse Light Soft",
719 palette: ThemePalette {
720 primary_accent: RgbColor(0x39, 0x3A, 0x34),
721 background: RgbColor(0xFA, 0xF5, 0xEB),
722 foreground: RgbColor(0x39, 0x3A, 0x34),
723 secondary_accent: RgbColor(0x1C, 0x6B, 0x48),
724 alert: RgbColor(0xA8, 0x57, 0x57),
725 logo_accent: RgbColor(0x9B, 0x63, 0x00),
726 },
727 },
728 );
729 map.insert(
730 "homebrew",
731 ThemeDefinition {
732 id: "homebrew",
733 label: "Homebrew",
734 palette: ThemePalette {
735 primary_accent: RgbColor(0xCC, 0xCC, 0xCC),
736 background: RgbColor(0x00, 0x00, 0x00),
737 foreground: RgbColor(0xCC, 0xCC, 0xCC),
738 secondary_accent: RgbColor(0x00, 0x99, 0xCC),
739 alert: RgbColor(0xD1, 0x45, 0x45),
740 logo_accent: RgbColor(0xCC, 0x99, 0x00),
741 },
742 },
743 );
744 map.insert(
745 "man-page",
746 ThemeDefinition {
747 id: "man-page",
748 label: "Man Page",
749 palette: ThemePalette {
750 primary_accent: RgbColor(0x00, 0x00, 0x00),
751 background: RgbColor(0xF2, 0xF2, 0xE6),
752 foreground: RgbColor(0x00, 0x00, 0x00),
753 secondary_accent: RgbColor(0x00, 0x66, 0x66),
754 alert: RgbColor(0x99, 0x00, 0x00),
755 logo_accent: RgbColor(0x7A, 0x5D, 0x00),
756 },
757 },
758 );
759 map.insert(
760 "framer",
761 ThemeDefinition {
762 id: "framer",
763 label: "Framer",
764 palette: ThemePalette {
765 primary_accent: RgbColor(0xF5, 0xF5, 0xF5),
766 background: RgbColor(0x10, 0x10, 0x10),
767 foreground: RgbColor(0xF5, 0xF5, 0xF5),
768 secondary_accent: RgbColor(0x81, 0x62, 0xFF),
769 alert: RgbColor(0xFF, 0x5C, 0x5C),
770 logo_accent: RgbColor(0xFF, 0xAF, 0x3F),
771 },
772 },
773 );
774 map.insert(
775 "espresso",
776 ThemeDefinition {
777 id: "espresso",
778 label: "Espresso",
779 palette: ThemePalette {
780 primary_accent: RgbColor(0xD0, 0xC8, 0xB8),
781 background: RgbColor(0x2A, 0x21, 0x1C),
782 foreground: RgbColor(0xD0, 0xC8, 0xB8),
783 secondary_accent: RgbColor(0x6F, 0xB3, 0xC2),
784 alert: RgbColor(0xD8, 0x6A, 0x6A),
785 logo_accent: RgbColor(0xC8, 0x92, 0x2D),
786 },
787 },
788 );
789 map.insert(
790 "adventure-time",
791 ThemeDefinition {
792 id: "adventure-time",
793 label: "Adventure Time",
794 palette: ThemePalette {
795 primary_accent: RgbColor(0xF8, 0xF8, 0xF8),
796 background: RgbColor(0x1F, 0x1D, 0x45),
797 foreground: RgbColor(0xF8, 0xF8, 0xF8),
798 secondary_accent: RgbColor(0x8A, 0x9B, 0xFF),
799 alert: RgbColor(0xDB, 0x67, 0x67),
800 logo_accent: RgbColor(0xF5, 0xB8, 0x4A),
801 },
802 },
803 );
804 map.insert(
805 "afterglow",
806 ThemeDefinition {
807 id: "afterglow",
808 label: "Afterglow",
809 palette: ThemePalette {
810 primary_accent: RgbColor(0xD6, 0xD6, 0xD6),
811 background: RgbColor(0x22, 0x22, 0x22),
812 foreground: RgbColor(0xD6, 0xD6, 0xD6),
813 secondary_accent: RgbColor(0x7F, 0xB0, 0xD0),
814 alert: RgbColor(0xE5, 0x72, 0x72),
815 logo_accent: RgbColor(0xD0, 0xA0, 0x60),
816 },
817 },
818 );
819 map.insert(
820 "mono",
821 ThemeDefinition {
822 id: "mono",
823 label: "Mono",
824 palette: ThemePalette {
825 primary_accent: RgbColor(0xFF, 0xFF, 0xFF),
826 background: RgbColor(0x00, 0x00, 0x00),
827 foreground: RgbColor(0xDB, 0xD7, 0xCA),
828 secondary_accent: RgbColor(0xBB, 0xBB, 0xBB),
829 alert: RgbColor(0xFF, 0xFF, 0xFF),
830 logo_accent: RgbColor(0xFF, 0xFF, 0xFF),
831 },
832 },
833 );
834 map.insert(
835 "ansi-classic",
836 ThemeDefinition {
837 id: "ansi-classic",
838 label: "ANSI Classic",
839 palette: ThemePalette {
840 primary_accent: RgbColor(0xC0, 0xC0, 0xC0),
841 background: RgbColor(0x00, 0x00, 0x00),
842 foreground: RgbColor(0xC0, 0xC0, 0xC0),
843 secondary_accent: RgbColor(0x00, 0xAA, 0xAA),
844 alert: RgbColor(0xC5, 0x52, 0x52),
845 logo_accent: RgbColor(0xAA, 0xAA, 0x00),
846 },
847 },
848 );
849
850 map.insert(
851 "nord",
852 ThemeDefinition {
853 id: "nord",
854 label: "Nord",
855 palette: ThemePalette {
856 primary_accent: RgbColor(0x88, 0xC0, 0xD0),
857 background: RgbColor(0x2E, 0x34, 0x40),
858 foreground: RgbColor(0xEC, 0xEF, 0xF4),
859 secondary_accent: RgbColor(0x81, 0xA1, 0xC1),
860 alert: RgbColor(0xCF, 0x88, 0x8F),
861 logo_accent: RgbColor(0xA3, 0xBE, 0x8C),
862 },
863 },
864 );
865 map.insert(
866 "nord-light",
867 ThemeDefinition {
868 id: "nord-light",
869 label: "Nord Light",
870 palette: ThemePalette {
871 primary_accent: RgbColor(0x52, 0x6E, 0x91),
872 background: RgbColor(0xEC, 0xEF, 0xF4),
873 foreground: RgbColor(0x2E, 0x34, 0x40),
874 secondary_accent: RgbColor(0x4C, 0x56, 0x6A),
875 alert: RgbColor(0x9B, 0x56, 0x60),
876 logo_accent: RgbColor(0x5D, 0x6E, 0x55),
877 },
878 },
879 );
880 map.insert(
881 "oxi",
882 ThemeDefinition {
883 id: "oxi",
884 label: "Oxi",
885 palette: ThemePalette {
886 primary_accent: RgbColor(0x8B, 0x94, 0x9E), background: RgbColor(0x0D, 0x11, 0x17), foreground: RgbColor(0xE6, 0xED, 0xF3), secondary_accent: RgbColor(0x58, 0xA6, 0xA6), alert: RgbColor(0xE0, 0x6C, 0x75), logo_accent: RgbColor(0x58, 0xA6, 0xA6), },
899 },
900 );
901 map.insert(
902 "oxide-dark",
903 ThemeDefinition {
904 id: "oxide-dark",
905 label: "Oxide Dark",
906 palette: ThemePalette {
907 primary_accent: RgbColor(0xC8, 0xC8, 0xC8), background: RgbColor(0x14, 0x14, 0x14), foreground: RgbColor(0xE1, 0xE1, 0xE1), secondary_accent: RgbColor(0x7A, 0xA2, 0xF7), alert: RgbColor(0xF7, 0x76, 0x8E), logo_accent: RgbColor(0xBB, 0x9A, 0xF7), },
918 },
919 );
920 register_catppuccin_themes(&mut map);
921 map
922});
923
924fn register_catppuccin_themes(map: &mut HashMap<&'static str, ThemeDefinition>) {
925 for &flavor_kind in CATPPUCCIN_FLAVORS {
926 let flavor = flavor_kind.flavor();
927 map.insert(
928 flavor_kind.id(),
929 ThemeDefinition {
930 id: flavor_kind.id(),
931 label: flavor_kind.label(),
932 palette: catppuccin_palette(flavor_kind, flavor),
933 },
934 );
935 }
936}
937
938fn catppuccin_palette(kind: CatppuccinFlavorKind, flavor: catppuccin::Flavor) -> ThemePalette {
939 let colors = flavor.colors;
940 if matches!(kind, CatppuccinFlavorKind::Latte) {
941 let darken = |c: catppuccin::Color| -> RgbColor {
942 RgbColor(
943 c.rgb.r.saturating_sub(32),
944 c.rgb.g.saturating_sub(32),
945 c.rgb.b.saturating_sub(32),
946 )
947 };
948 ThemePalette {
950 primary_accent: catppuccin_rgb(colors.mauve),
951 background: catppuccin_rgb(colors.base),
952 foreground: catppuccin_rgb(colors.text),
953 secondary_accent: darken(colors.blue),
954 alert: catppuccin_rgb(colors.red),
955 logo_accent: darken(colors.maroon),
956 }
957 } else {
958 ThemePalette {
959 primary_accent: catppuccin_rgb(colors.lavender),
960 background: catppuccin_rgb(colors.base),
961 foreground: catppuccin_rgb(colors.text),
962 secondary_accent: catppuccin_rgb(colors.sapphire),
963 alert: catppuccin_rgb(colors.red),
964 logo_accent: catppuccin_rgb(colors.peach),
965 }
966 }
967}
968
969fn catppuccin_rgb(color: catppuccin::Color) -> RgbColor {
970 RgbColor(color.rgb.r, color.rgb.g, color.rgb.b)
971}
972
973pub(crate) fn theme_definition(theme_id: &str) -> Option<&'static ThemeDefinition> {
974 REGISTRY.get(theme_id)
975}
976
977#[cfg(test)]
978pub(crate) fn all_theme_definitions() -> &'static HashMap<&'static str, ThemeDefinition> {
979 ®ISTRY
980}
981
982pub fn available_themes() -> Vec<&'static str> {
984 let mut keys: Vec<&'static str> = REGISTRY.keys().copied().collect();
985 keys.sort_unstable();
986 keys
987}
988
989pub fn theme_label(theme_id: &str) -> Option<&'static str> {
991 theme_definition(theme_id).map(|definition| definition.label)
992}
993
994fn suite_id_for_theme(theme_id: &str) -> Option<&'static str> {
995 if theme_id.starts_with("nord") {
996 Some("nord")
997 } else if theme_id.starts_with("catppuccin-") {
998 Some("catppuccin")
999 } else if theme_id.starts_with("vitesse-") {
1000 Some("vitesse")
1001 } else if theme_id.starts_with("ciapre-") {
1002 Some("ciapre")
1003 } else if theme_id.starts_with("oxide-") {
1004 Some("oxide")
1005 } else if theme_id == "mono" {
1006 Some("mono")
1007 } else if theme_id == "oxi" {
1008 Some("oxi")
1009 } else {
1010 None
1011 }
1012}
1013
1014fn suite_label(suite_id: &str) -> Option<&'static str> {
1015 match suite_id {
1016 "nord" => Some("Nord"),
1017 "catppuccin" => Some("Catppuccin"),
1018 "vitesse" => Some("Vitesse"),
1019 "oxide" => Some("Oxide"),
1020 "oxi" => Some("Oxi"),
1021 "ciapre" => Some("Ciapre"),
1022 "mono" => Some("Mono"),
1023 _ => None,
1024 }
1025}
1026
1027pub fn theme_suite_id(theme_id: &str) -> Option<&'static str> {
1029 suite_id_for_theme(theme_id)
1030}
1031
1032pub fn theme_suite_label(theme_id: &str) -> Option<&'static str> {
1034 suite_id_for_theme(theme_id).and_then(suite_label)
1035}
1036
1037pub fn available_theme_suites() -> Vec<ThemeSuite> {
1039 const ORDER: &[&str] = &[
1040 "oxi",
1041 "oxide",
1042 "ciapre",
1043 "vitesse",
1044 "catppuccin",
1045 "mono",
1046 "nord",
1047 ];
1048
1049 ORDER
1050 .iter()
1051 .filter_map(|suite_id| {
1052 let mut theme_ids: Vec<&'static str> = available_themes()
1053 .into_iter()
1054 .filter(|theme_id| suite_id_for_theme(theme_id) == Some(*suite_id))
1055 .collect();
1056 if theme_ids.is_empty() {
1057 return None;
1058 }
1059 theme_ids.sort_unstable();
1060 Some(ThemeSuite {
1061 id: suite_id,
1062 label: suite_label(suite_id)?,
1063 theme_ids,
1064 })
1065 })
1066 .collect()
1067}