Skip to main content

merman_render/presentation/
presets.rs

1use super::{HostTheme, HostThemeAppearance, PresentationError};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4#[non_exhaustive]
5pub enum HostThemePreset {
6    #[default]
7    EditorLight,
8    EditorDark,
9    OneDark,
10    GruvboxLight,
11    GruvboxDark,
12    AyuLight,
13    AyuDark,
14}
15
16impl HostThemePreset {
17    pub const ALL: [Self; 7] = [
18        Self::EditorLight,
19        Self::EditorDark,
20        Self::OneDark,
21        Self::GruvboxLight,
22        Self::GruvboxDark,
23        Self::AyuLight,
24        Self::AyuDark,
25    ];
26
27    pub const fn id(self) -> &'static str {
28        match self {
29            Self::EditorLight => "editor-light",
30            Self::EditorDark => "editor-dark",
31            Self::OneDark => "one-dark",
32            Self::GruvboxLight => "gruvbox-light",
33            Self::GruvboxDark => "gruvbox-dark",
34            Self::AyuLight => "ayu-light",
35            Self::AyuDark => "ayu-dark",
36        }
37    }
38
39    pub fn from_id(id: &str) -> Result<Self, PresentationError> {
40        Self::ALL
41            .into_iter()
42            .find(|preset| preset.id() == id)
43            .ok_or_else(|| PresentationError::UnknownThemePreset(id.to_string()))
44    }
45
46    pub const fn appearance(self) -> HostThemeAppearance {
47        match self {
48            Self::EditorLight | Self::GruvboxLight | Self::AyuLight => HostThemeAppearance::Light,
49            Self::EditorDark | Self::OneDark | Self::GruvboxDark | Self::AyuDark => {
50                HostThemeAppearance::Dark
51            }
52        }
53    }
54
55    pub(crate) fn theme(self) -> HostTheme {
56        let (roles, palette) = match self {
57            Self::EditorLight => (EDITOR_LIGHT_ROLES, EDITOR_LIGHT_PALETTE),
58            Self::EditorDark => (EDITOR_DARK_ROLES, EDITOR_DARK_PALETTE),
59            Self::OneDark => (ONE_DARK_ROLES, ONE_DARK_PALETTE),
60            Self::GruvboxLight => (GRUVBOX_LIGHT_ROLES, GRUVBOX_LIGHT_PALETTE),
61            Self::GruvboxDark => (GRUVBOX_DARK_ROLES, GRUVBOX_DARK_PALETTE),
62            Self::AyuLight => (AYU_LIGHT_ROLES, AYU_LIGHT_PALETTE),
63            Self::AyuDark => (AYU_DARK_ROLES, AYU_DARK_PALETTE),
64        };
65        HostTheme::bundled(self.appearance(), roles, palette)
66    }
67}
68
69const EDITOR_LIGHT_ROLES: &[(super::ThemeRole, &str)] = &[
70    (super::ThemeRole::Canvas, "#ffffff"),
71    (super::ThemeRole::Surface, "#f8fafc"),
72    (super::ThemeRole::SurfaceAlt, "#e2e8f0"),
73    (super::ThemeRole::SurfaceMuted, "#f1f5f9"),
74    (super::ThemeRole::Text, "#0f172a"),
75    (super::ThemeRole::SubtleText, "#475569"),
76    (super::ThemeRole::Border, "#94a3b8"),
77    (super::ThemeRole::Line, "#64748b"),
78    (super::ThemeRole::EdgeLabelBackground, "#ffffff"),
79    (super::ThemeRole::ClusterBackground, "#f1f5f9"),
80    (super::ThemeRole::ClusterBorder, "#cbd5e1"),
81    (super::ThemeRole::NoteBackground, "#fff7ed"),
82    (super::ThemeRole::NoteBorder, "#fdba74"),
83    (super::ThemeRole::NoteText, "#7c2d12"),
84    (super::ThemeRole::ActorBackground, "#f8fafc"),
85    (super::ThemeRole::ActorBorder, "#94a3b8"),
86    (super::ThemeRole::ActorText, "#0f172a"),
87    (super::ThemeRole::ActivationBackground, "#e2e8f0"),
88    (super::ThemeRole::ActivationBorder, "#94a3b8"),
89    (super::ThemeRole::Error, "#dc2626"),
90    (super::ThemeRole::Warning, "#d97706"),
91    (super::ThemeRole::Success, "#059669"),
92];
93const EDITOR_LIGHT_PALETTE: &[&str] = &[
94    "#2563eb", "#059669", "#d97706", "#7c3aed", "#0891b2", "#be123c", "#a16207", "#65a30d",
95];
96
97const EDITOR_DARK_ROLES: &[(super::ThemeRole, &str)] = &[
98    (super::ThemeRole::Canvas, "#0f172a"),
99    (super::ThemeRole::Surface, "#111827"),
100    (super::ThemeRole::SurfaceAlt, "#1f2937"),
101    (super::ThemeRole::SurfaceMuted, "#334155"),
102    (super::ThemeRole::Text, "#e5e7eb"),
103    (super::ThemeRole::SubtleText, "#cbd5e1"),
104    (super::ThemeRole::Border, "#475569"),
105    (super::ThemeRole::Line, "#94a3b8"),
106    (super::ThemeRole::EdgeLabelBackground, "#0f172a"),
107    (super::ThemeRole::ClusterBackground, "#1e293b"),
108    (super::ThemeRole::ClusterBorder, "#475569"),
109    (super::ThemeRole::NoteBackground, "#422006"),
110    (super::ThemeRole::NoteBorder, "#f59e0b"),
111    (super::ThemeRole::NoteText, "#fef3c7"),
112    (super::ThemeRole::ActorBackground, "#1f2937"),
113    (super::ThemeRole::ActorBorder, "#475569"),
114    (super::ThemeRole::ActorText, "#e5e7eb"),
115    (super::ThemeRole::ActivationBackground, "#334155"),
116    (super::ThemeRole::ActivationBorder, "#64748b"),
117    (super::ThemeRole::Error, "#f87171"),
118    (super::ThemeRole::Warning, "#fbbf24"),
119    (super::ThemeRole::Success, "#34d399"),
120];
121const EDITOR_DARK_PALETTE: &[&str] = &[
122    "#60a5fa", "#34d399", "#f59e0b", "#c084fc", "#22d3ee", "#fb7185", "#facc15", "#a3e635",
123];
124
125const ONE_DARK_ROLES: &[(super::ThemeRole, &str)] = &[
126    (super::ThemeRole::Canvas, "#282c34"),
127    (super::ThemeRole::Surface, "#21252b"),
128    (super::ThemeRole::SurfaceAlt, "#2c313a"),
129    (super::ThemeRole::SurfaceMuted, "#3e4451"),
130    (super::ThemeRole::Text, "#abb2bf"),
131    (super::ThemeRole::SubtleText, "#abb2bf"),
132    (super::ThemeRole::Border, "#3e4451"),
133    (super::ThemeRole::Line, "#61afef"),
134    (super::ThemeRole::EdgeLabelBackground, "#282c34"),
135    (super::ThemeRole::ClusterBackground, "#2c313a"),
136    (super::ThemeRole::ClusterBorder, "#3e4451"),
137    (super::ThemeRole::NoteBackground, "#3a2f1b"),
138    (super::ThemeRole::NoteBorder, "#e5c07b"),
139    (super::ThemeRole::NoteText, "#f0dca4"),
140    (super::ThemeRole::ActorBackground, "#2c313a"),
141    (super::ThemeRole::ActorBorder, "#3e4451"),
142    (super::ThemeRole::ActorText, "#abb2bf"),
143    (super::ThemeRole::ActivationBackground, "#3e4451"),
144    (super::ThemeRole::ActivationBorder, "#5c6370"),
145    (super::ThemeRole::Error, "#e06c75"),
146    (super::ThemeRole::Warning, "#e5c07b"),
147    (super::ThemeRole::Success, "#98c379"),
148];
149const ONE_DARK_PALETTE: &[&str] = &[
150    "#61afef", "#98c379", "#e5c07b", "#c678dd", "#56b6c2", "#e06c75", "#d19a66", "#be5046",
151];
152
153const GRUVBOX_LIGHT_ROLES: &[(super::ThemeRole, &str)] = &[
154    (super::ThemeRole::Canvas, "#fbf1c7"),
155    (super::ThemeRole::Surface, "#f2e5bc"),
156    (super::ThemeRole::SurfaceAlt, "#ebdbb2"),
157    (super::ThemeRole::SurfaceMuted, "#d5c4a1"),
158    (super::ThemeRole::Text, "#3c3836"),
159    (super::ThemeRole::SubtleText, "#665c54"),
160    (super::ThemeRole::Border, "#d5c4a1"),
161    (super::ThemeRole::Line, "#7c6f64"),
162    (super::ThemeRole::EdgeLabelBackground, "#fbf1c7"),
163    (super::ThemeRole::ClusterBackground, "#ebdbb2"),
164    (super::ThemeRole::ClusterBorder, "#d5c4a1"),
165    (super::ThemeRole::NoteBackground, "#f2e5bc"),
166    (super::ThemeRole::NoteBorder, "#d79921"),
167    (super::ThemeRole::NoteText, "#3c3836"),
168    (super::ThemeRole::ActorBackground, "#ebdbb2"),
169    (super::ThemeRole::ActorBorder, "#d5c4a1"),
170    (super::ThemeRole::ActorText, "#3c3836"),
171    (super::ThemeRole::ActivationBackground, "#d5c4a1"),
172    (super::ThemeRole::ActivationBorder, "#bdae93"),
173    (super::ThemeRole::Error, "#cc241d"),
174    (super::ThemeRole::Warning, "#d79921"),
175    (super::ThemeRole::Success, "#98971a"),
176];
177const GRUVBOX_LIGHT_PALETTE: &[&str] = &[
178    "#458588", "#98971a", "#d79921", "#b16286", "#689d6a", "#cc241d", "#d65d0e", "#427b58",
179];
180
181const GRUVBOX_DARK_ROLES: &[(super::ThemeRole, &str)] = &[
182    (super::ThemeRole::Canvas, "#282828"),
183    (super::ThemeRole::Surface, "#3c3836"),
184    (super::ThemeRole::SurfaceAlt, "#504945"),
185    (super::ThemeRole::SurfaceMuted, "#665c54"),
186    (super::ThemeRole::Text, "#ebdbb2"),
187    (super::ThemeRole::SubtleText, "#d5c4a1"),
188    (super::ThemeRole::Border, "#665c54"),
189    (super::ThemeRole::Line, "#d5c4a1"),
190    (super::ThemeRole::EdgeLabelBackground, "#282828"),
191    (super::ThemeRole::ClusterBackground, "#3c3836"),
192    (super::ThemeRole::ClusterBorder, "#665c54"),
193    (super::ThemeRole::NoteBackground, "#3c3836"),
194    (super::ThemeRole::NoteBorder, "#fabd2f"),
195    (super::ThemeRole::NoteText, "#fbf1c7"),
196    (super::ThemeRole::ActorBackground, "#3c3836"),
197    (super::ThemeRole::ActorBorder, "#665c54"),
198    (super::ThemeRole::ActorText, "#ebdbb2"),
199    (super::ThemeRole::ActivationBackground, "#504945"),
200    (super::ThemeRole::ActivationBorder, "#7c6f64"),
201    (super::ThemeRole::Error, "#fb4934"),
202    (super::ThemeRole::Warning, "#fabd2f"),
203    (super::ThemeRole::Success, "#b8bb26"),
204];
205const GRUVBOX_DARK_PALETTE: &[&str] = &[
206    "#83a598", "#b8bb26", "#fabd2f", "#d3869b", "#8ec07c", "#fb4934", "#fe8019", "#689d6a",
207];
208
209const AYU_LIGHT_ROLES: &[(super::ThemeRole, &str)] = &[
210    (super::ThemeRole::Canvas, "#fcfcfc"),
211    (super::ThemeRole::Surface, "#f3f4f5"),
212    (super::ThemeRole::SurfaceAlt, "#e6e8eb"),
213    (super::ThemeRole::SurfaceMuted, "#d9d7ce"),
214    (super::ThemeRole::Text, "#5c6166"),
215    (super::ThemeRole::SubtleText, "#5c6166"),
216    (super::ThemeRole::Border, "#8a9199"),
217    (super::ThemeRole::Line, "#5c6166"),
218    (super::ThemeRole::EdgeLabelBackground, "#fcfcfc"),
219    (super::ThemeRole::ClusterBackground, "#f3f4f5"),
220    (super::ThemeRole::ClusterBorder, "#8a9199"),
221    (super::ThemeRole::NoteBackground, "#fff3bf"),
222    (super::ThemeRole::NoteBorder, "#ffaa33"),
223    (super::ThemeRole::NoteText, "#5c6166"),
224    (super::ThemeRole::ActorBackground, "#f3f4f5"),
225    (super::ThemeRole::ActorBorder, "#8a9199"),
226    (super::ThemeRole::ActorText, "#5c6166"),
227    (super::ThemeRole::ActivationBackground, "#e6e8eb"),
228    (super::ThemeRole::ActivationBorder, "#8a9199"),
229    (super::ThemeRole::Error, "#f07171"),
230    (super::ThemeRole::Warning, "#ffaa33"),
231    (super::ThemeRole::Success, "#86b300"),
232];
233const AYU_LIGHT_PALETTE: &[&str] = &[
234    "#55b4d4", "#86b300", "#ffaa33", "#a37acc", "#4cbf99", "#f07171", "#f2ae49", "#399ee6",
235];
236
237const AYU_DARK_ROLES: &[(super::ThemeRole, &str)] = &[
238    (super::ThemeRole::Canvas, "#0b0e14"),
239    (super::ThemeRole::Surface, "#11151c"),
240    (super::ThemeRole::SurfaceAlt, "#1f2430"),
241    (super::ThemeRole::SurfaceMuted, "#343b48"),
242    (super::ThemeRole::Text, "#bfbdb6"),
243    (super::ThemeRole::SubtleText, "#8a9199"),
244    (super::ThemeRole::Border, "#343b48"),
245    (super::ThemeRole::Line, "#59c2ff"),
246    (super::ThemeRole::EdgeLabelBackground, "#0b0e14"),
247    (super::ThemeRole::ClusterBackground, "#1f2430"),
248    (super::ThemeRole::ClusterBorder, "#343b48"),
249    (super::ThemeRole::NoteBackground, "#332a14"),
250    (super::ThemeRole::NoteBorder, "#ffb454"),
251    (super::ThemeRole::NoteText, "#ffdf99"),
252    (super::ThemeRole::ActorBackground, "#1f2430"),
253    (super::ThemeRole::ActorBorder, "#343b48"),
254    (super::ThemeRole::ActorText, "#bfbdb6"),
255    (super::ThemeRole::ActivationBackground, "#343b48"),
256    (super::ThemeRole::ActivationBorder, "#4f5866"),
257    (super::ThemeRole::Error, "#f07178"),
258    (super::ThemeRole::Warning, "#ffb454"),
259    (super::ThemeRole::Success, "#aad94c"),
260];
261const AYU_DARK_PALETTE: &[&str] = &[
262    "#59c2ff", "#aad94c", "#ffb454", "#d2a6ff", "#95e6cb", "#f07178", "#f29668", "#39bae6",
263];
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq)]
266pub struct ThemePresetDescriptor {
267    preset: HostThemePreset,
268}
269
270impl ThemePresetDescriptor {
271    pub const fn id(&self) -> &'static str {
272        self.preset.id()
273    }
274
275    pub const fn appearance(&self) -> HostThemeAppearance {
276        self.preset.appearance()
277    }
278}
279
280const THEME_PRESET_DESCRIPTORS: [ThemePresetDescriptor; 7] = [
281    ThemePresetDescriptor {
282        preset: HostThemePreset::EditorLight,
283    },
284    ThemePresetDescriptor {
285        preset: HostThemePreset::EditorDark,
286    },
287    ThemePresetDescriptor {
288        preset: HostThemePreset::OneDark,
289    },
290    ThemePresetDescriptor {
291        preset: HostThemePreset::GruvboxLight,
292    },
293    ThemePresetDescriptor {
294        preset: HostThemePreset::GruvboxDark,
295    },
296    ThemePresetDescriptor {
297        preset: HostThemePreset::AyuLight,
298    },
299    ThemePresetDescriptor {
300        preset: HostThemePreset::AyuDark,
301    },
302];
303
304pub const fn theme_preset_descriptors() -> &'static [ThemePresetDescriptor] {
305    &THEME_PRESET_DESCRIPTORS
306}