1const LIGHT: &str = r#"
2:root {
3 --bg: #faf9f5;
4 --bg-sub: #f3f1ea;
5 --bg-card: #ffffff;
6 --bg-code: #f0ede4;
7 --bd: #e5e1d6;
8 --bd-sub: #ede9df;
9 --t1: #1f1e1d;
10 --t2: #5c5852;
11 --t3: #9c9589;
12 --t4: #c4beb4;
13 --accent: #c96442;
14 --accent-h: #b5572d;
15 --accent-bg: #f9ede8;
16 --green: #2d8a4e;
17 --orange: #b56613;
18 --red: #c0392b;
19 --purple: #7952b3;
20 --cyan: #1a7a8a;
21 --blue: #1c6bbb;
22 --s2xx: #2d8a4e;
23 --s3xx: #1a7a8a;
24 --s4xx: #b56613;
25 --s5xx: #c0392b;
26 --sb-t: #eceae2;
27 --sb-th: #c8c3b8;
28 --shadow-sm: 0 1px 2px rgba(31, 30, 29, 0.06);
29 --shadow-md: 0 4px 12px rgba(31, 30, 29, 0.1);
30}
31"#;
32
33const DARK: &str = r#"
34[data-theme="dark"] {
35 --bg: #1e1c19;
36 --bg-sub: #252320;
37 --bg-card: #2d2b27;
38 --bg-code: #201f1c;
39 --bd: #3a3733;
40 --bd-sub: #302e2b;
41 --t1: #ede8df;
42 --t2: #9c9487;
43 --t3: #6b6560;
44 --t4: #3d3a36;
45 --accent: #d4714f;
46 --accent-h: #e07d5a;
47 --accent-bg: #2e2119;
48 --green: #4caf72;
49 --orange: #d4943a;
50 --red: #e05c4b;
51 --purple: #a07fd0;
52 --cyan: #38bcd4;
53 --blue: #5a9fe0;
54 --s2xx: #4caf72;
55 --s3xx: #38bcd4;
56 --s4xx: #d4943a;
57 --s5xx: #e05c4b;
58 --sb-t: #252320;
59 --sb-th: #3a3733;
60 --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
61 --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
62}
63"#;
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
66pub enum ThemeMode {
67 Light,
69 Dark,
71 #[default]
73 System,
74}
75
76impl ThemeMode {
77 pub fn from_str(s: &str) -> Self {
79 match s.to_lowercase().as_str() {
80 "light" => ThemeMode::Light,
81 "dark" => ThemeMode::Dark,
82 _ => ThemeMode::System,
83 }
84 }
85
86 pub fn as_str(&self) -> &'static str {
88 match self {
89 ThemeMode::Light => "light",
90 ThemeMode::Dark => "dark",
91 ThemeMode::System => "system",
92 }
93 }
94
95 pub fn get_css(&self) -> String {
96 match self {
97 ThemeMode::Light => LIGHT.to_string(),
98 ThemeMode::Dark => DARK.to_string(),
99 ThemeMode::System => format!("{}{}", LIGHT, DARK),
100 }
101 }
102}
103
104pub fn get_theme_css(theme: &str) -> String {
105 ThemeMode::from_str(theme).get_css()
106}
107
108pub fn get_complete_theme_css() -> String {
109 ThemeMode::System.get_css()
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_theme_mode_from_str() {
118 assert_eq!(ThemeMode::from_str("dark"), ThemeMode::Dark);
119 assert_eq!(ThemeMode::from_str("DARK"), ThemeMode::Dark);
120 assert_eq!(ThemeMode::from_str("light"), ThemeMode::Light);
121 assert_eq!(ThemeMode::from_str("system"), ThemeMode::System);
122 assert_eq!(ThemeMode::from_str(""), ThemeMode::System);
123 }
124
125 #[test]
126 fn test_theme_mode_get_css() {
127 let light_css = ThemeMode::Light.get_css();
128 assert!(light_css.contains(":root"));
129 assert!(!light_css.contains("[data-theme=\"dark\"]"));
130
131 let dark_css = ThemeMode::Dark.get_css();
132 assert!(dark_css.contains("[data-theme=\"dark\"]"));
133
134 let system_css = ThemeMode::System.get_css();
135 assert!(system_css.contains(":root"));
136 assert!(system_css.contains("[data-theme=\"dark\"]"));
137 }
138
139 #[test]
140 fn test_get_theme_css() {
141 let css = get_theme_css("");
142 assert!(css.contains(":root"));
143 assert!(css.contains("[data-theme=\"dark\"]"));
144
145 let css = get_theme_css("dark");
146 assert!(css.contains("[data-theme=\"dark\"]"));
147
148 let css = get_theme_css("light");
149 assert!(css.contains(":root"));
150 }
151
152 #[test]
153 fn test_get_complete_theme_css() {
154 let css = get_complete_theme_css();
155 assert!(css.contains(":root"));
156 assert!(css.contains("[data-theme=\"dark\"]"));
157 }
158}