1use super::{Color, Theme};
6
7pub const PRESET_NAMES: [&str; 6] = [
9 "catppuccin",
10 "nord",
11 "tokyonight",
12 "gruvbox",
13 "dracula",
14 "solarizedlight",
15];
16
17fn hex(value: &'static str) -> Color {
18 Color::hex(value)
19}
20
21impl Theme {
22 pub fn preset(name: &str) -> Option<Theme> {
24 match name {
25 "catppuccin" => Some(Theme::catppuccin()),
26 "nord" => Some(Theme::nord()),
27 "tokyonight" => Some(Theme::tokyonight()),
28 "gruvbox" => Some(Theme::gruvbox()),
29 "dracula" => Some(Theme::dracula()),
30 "solarizedlight" => Some(Theme::solarized_light()),
31 _ => None,
32 }
33 }
34
35 pub fn catppuccin() -> Theme {
37 Theme::dark()
38 .with_primary(hex("#89b4fa"))
39 .with_body(hex("#1e1e2e"))
40 .with_surface(hex("#181825"))
41 .with_surface_hover(hex("#313244"))
42 .with_text(hex("#cdd6f4"))
43 .with_dimmed(hex("#a6adc8"))
44 .with_border(hex("#45475a"))
45 .with_success(hex("#a6e3a1"))
46 .with_warning(hex("#f9e2af"))
47 .with_danger(hex("#f38ba8"))
48 .with_info(hex("#89dceb"))
49 }
50
51 pub fn nord() -> Theme {
53 Theme::dark()
54 .with_primary(hex("#88c0d0"))
55 .with_body(hex("#2e3440"))
56 .with_surface(hex("#3b4252"))
57 .with_surface_hover(hex("#434c5e"))
58 .with_text(hex("#eceff4"))
59 .with_dimmed(hex("#d8dee9"))
60 .with_border(hex("#4c566a"))
61 .with_success(hex("#a3be8c"))
62 .with_warning(hex("#ebcb8b"))
63 .with_danger(hex("#bf616a"))
64 .with_info(hex("#81a1c1"))
65 }
66
67 pub fn tokyonight() -> Theme {
69 Theme::dark()
70 .with_primary(hex("#7aa2f7"))
71 .with_body(hex("#1a1b26"))
72 .with_surface(hex("#16161e"))
73 .with_surface_hover(hex("#292e42"))
74 .with_text(hex("#c0caf5"))
75 .with_dimmed(hex("#565f89"))
76 .with_border(hex("#3b4261"))
77 .with_success(hex("#9ece6a"))
78 .with_warning(hex("#e0af68"))
79 .with_danger(hex("#f7768e"))
80 .with_info(hex("#7dcfff"))
81 }
82
83 pub fn gruvbox() -> Theme {
85 Theme::dark()
86 .with_primary(hex("#fe8019"))
87 .with_body(hex("#282828"))
88 .with_surface(hex("#3c3836"))
89 .with_surface_hover(hex("#504945"))
90 .with_text(hex("#ebdbb2"))
91 .with_dimmed(hex("#a89984"))
92 .with_border(hex("#665c54"))
93 .with_success(hex("#b8bb26"))
94 .with_warning(hex("#fabd2f"))
95 .with_danger(hex("#fb4934"))
96 .with_info(hex("#83a598"))
97 }
98
99 pub fn dracula() -> Theme {
101 Theme::dark()
102 .with_primary(hex("#bd93f9"))
103 .with_body(hex("#282a36"))
104 .with_surface(hex("#21222c"))
105 .with_surface_hover(hex("#44475a"))
106 .with_text(hex("#f8f8f2"))
107 .with_dimmed(hex("#6272a4"))
108 .with_border(hex("#44475a"))
109 .with_success(hex("#50fa7b"))
110 .with_warning(hex("#f1fa8c"))
111 .with_danger(hex("#ff5555"))
112 .with_info(hex("#8be9fd"))
113 }
114
115 pub fn solarized_light() -> Theme {
117 Theme::light()
118 .with_primary(hex("#268bd2"))
119 .with_body(hex("#fdf6e3"))
120 .with_surface(hex("#eee8d5"))
121 .with_surface_hover(hex("#e4dcc4"))
122 .with_text(hex("#657b83"))
123 .with_dimmed(hex("#93a1a1"))
124 .with_border(hex("#d5cdb4"))
125 .with_success(hex("#859900"))
126 .with_warning(hex("#b58900"))
127 .with_danger(hex("#dc322f"))
128 .with_info(hex("#2aa198"))
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn every_name_resolves_and_overrides_all_slots() {
138 for name in PRESET_NAMES {
139 let theme = Theme::preset(name).unwrap_or_else(|| panic!("missing preset {name}"));
140 let o = &theme.overrides;
141 for (slot, value) in [
142 ("primary", o.primary),
143 ("body", o.body),
144 ("surface", o.surface),
145 ("surface_hover", o.surface_hover),
146 ("text", o.text),
147 ("dimmed", o.dimmed),
148 ("border", o.border),
149 ("success", o.success),
150 ("warning", o.warning),
151 ("danger", o.danger),
152 ("info", o.info),
153 ] {
154 assert!(value.is_some(), "{name} leaves {slot} unset");
155 }
156 }
157 assert!(Theme::preset("nope").is_none());
158 }
159
160 #[test]
161 fn presets_pick_sensible_schemes() {
162 assert!(Theme::catppuccin().scheme.is_dark());
163 assert!(!Theme::solarized_light().scheme.is_dark());
164 }
165}