1use crate::core::color::Color;
2use crate::style::Style;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct ThemeTokens {
6 pub panel: Color,
7 pub text: Color,
8 pub dim: Color,
9 pub accent: Color,
10 pub success: Color,
11 pub warning: Color,
12 pub error: Color,
13}
14
15impl ThemeTokens {
16 pub const SCRIN: Self = Self {
17 panel: Color::rgb(22, 27, 34),
18 text: Color::rgb(201, 209, 217),
19 dim: Color::rgb(110, 118, 129),
20 accent: Color::rgb(88, 166, 255),
21 success: Color::rgb(63, 185, 80),
22 warning: Color::rgb(210, 153, 34),
23 error: Color::rgb(248, 81, 73),
24 };
25
26 pub const fn new(
27 panel: Color,
28 text: Color,
29 dim: Color,
30 accent: Color,
31 success: Color,
32 warning: Color,
33 error: Color,
34 ) -> Self {
35 Self {
36 panel,
37 text,
38 dim,
39 accent,
40 success,
41 warning,
42 error,
43 }
44 }
45
46 pub const fn panel_style(self) -> Style {
47 Style::new().fg(self.text).bg(self.panel)
48 }
49
50 pub const fn text_style(self) -> Style {
51 Style::new().fg(self.text)
52 }
53
54 pub const fn dim_style(self) -> Style {
55 Style::new().fg(self.dim)
56 }
57
58 pub const fn accent_style(self) -> Style {
59 Style::new().fg(self.accent)
60 }
61
62 pub const fn success_style(self) -> Style {
63 Style::new().fg(self.success)
64 }
65
66 pub const fn warning_style(self) -> Style {
67 Style::new().fg(self.warning)
68 }
69
70 pub const fn error_style(self) -> Style {
71 Style::new().fg(self.error)
72 }
73}
74
75impl Default for ThemeTokens {
76 fn default() -> Self {
77 Self::SCRIN
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq)]
82pub struct Theme {
83 pub bg: Color,
84 pub fg: Color,
85 pub accent: Color,
86 pub accent_bright: Color,
87 pub muted: Color,
88 pub surface: Color,
89 pub surface_bright: Color,
90 pub error: Color,
91 pub warning: Color,
92 pub success: Color,
93 pub info: Color,
94 pub border: Color,
95 pub border_focus: Color,
96 pub text_primary: Color,
97 pub text_secondary: Color,
98 pub text_dim: Color,
99 pub highlight_bg: Color,
100 pub highlight_fg: Color,
101 pub glow: Color,
102}
103
104impl Theme {
105 pub const DARK: Theme = Theme {
106 bg: Color::rgb(13, 17, 23),
107 fg: Color::rgb(201, 209, 217),
108 accent: Color::rgb(88, 166, 255),
109 accent_bright: Color::rgb(121, 192, 255),
110 muted: Color::rgb(110, 118, 129),
111 surface: Color::rgb(22, 27, 34),
112 surface_bright: Color::rgb(33, 38, 45),
113 error: Color::rgb(248, 81, 73),
114 warning: Color::rgb(210, 153, 34),
115 success: Color::rgb(63, 185, 80),
116 info: Color::rgb(56, 139, 253),
117 border: Color::rgb(48, 54, 61),
118 border_focus: Color::rgb(88, 166, 255),
119 text_primary: Color::rgb(201, 209, 217),
120 text_secondary: Color::rgb(139, 148, 158),
121 text_dim: Color::rgb(110, 118, 129),
122 highlight_bg: Color::rgb(31, 111, 235),
123 highlight_fg: Color::rgb(255, 255, 255),
124 glow: Color::rgb(88, 166, 255),
125 };
126
127 pub const CYBERPUNK: Theme = Theme {
128 bg: Color::rgb(10, 4, 18),
129 fg: Color::rgb(200, 200, 255),
130 accent: Color::rgb(255, 0, 128),
131 accent_bright: Color::rgb(255, 80, 180),
132 muted: Color::rgb(100, 60, 140),
133 surface: Color::rgb(20, 10, 35),
134 surface_bright: Color::rgb(35, 18, 55),
135 error: Color::rgb(255, 30, 30),
136 warning: Color::rgb(255, 200, 0),
137 success: Color::rgb(0, 255, 128),
138 info: Color::rgb(0, 200, 255),
139 border: Color::rgb(60, 30, 90),
140 border_focus: Color::rgb(255, 0, 128),
141 text_primary: Color::rgb(220, 220, 255),
142 text_secondary: Color::rgb(150, 130, 180),
143 text_dim: Color::rgb(90, 70, 120),
144 highlight_bg: Color::rgb(255, 0, 128),
145 highlight_fg: Color::rgb(255, 255, 255),
146 glow: Color::rgb(255, 0, 128),
147 };
148
149 pub const MONOKAI: Theme = Theme {
150 bg: Color::rgb(39, 40, 34),
151 fg: Color::rgb(248, 248, 242),
152 accent: Color::rgb(166, 226, 46),
153 accent_bright: Color::rgb(171, 227, 56),
154 muted: Color::rgb(117, 113, 94),
155 surface: Color::rgb(49, 50, 44),
156 surface_bright: Color::rgb(69, 71, 66),
157 error: Color::rgb(249, 38, 114),
158 warning: Color::rgb(230, 219, 100),
159 success: Color::rgb(166, 226, 46),
160 info: Color::rgb(102, 217, 239),
161 border: Color::rgb(79, 82, 76),
162 border_focus: Color::rgb(166, 226, 46),
163 text_primary: Color::rgb(248, 248, 242),
164 text_secondary: Color::rgb(171, 174, 167),
165 text_dim: Color::rgb(117, 113, 94),
166 highlight_bg: Color::rgb(73, 72, 62),
167 highlight_fg: Color::rgb(255, 255, 255),
168 glow: Color::rgb(166, 226, 46),
169 };
170
171 pub const SOLARIZED: Theme = Theme {
172 bg: Color::rgb(0, 43, 54),
173 fg: Color::rgb(131, 148, 150),
174 accent: Color::rgb(38, 139, 210),
175 accent_bright: Color::rgb(42, 161, 152),
176 muted: Color::rgb(88, 110, 117),
177 surface: Color::rgb(7, 54, 66),
178 surface_bright: Color::rgb(0, 63, 77),
179 error: Color::rgb(220, 50, 47),
180 warning: Color::rgb(181, 137, 0),
181 success: Color::rgb(133, 153, 0),
182 info: Color::rgb(42, 161, 152),
183 border: Color::rgb(88, 110, 117),
184 border_focus: Color::rgb(38, 139, 210),
185 text_primary: Color::rgb(147, 161, 161),
186 text_secondary: Color::rgb(108, 113, 118),
187 text_dim: Color::rgb(88, 110, 117),
188 highlight_bg: Color::rgb(0, 63, 77),
189 highlight_fg: Color::rgb(253, 246, 227),
190 glow: Color::rgb(42, 161, 152),
191 };
192
193 pub fn accent_for(&self, index: usize) -> Color {
194 let colors = [
195 self.accent,
196 self.success,
197 self.warning,
198 self.error,
199 self.info,
200 Color::rgb(188, 140, 255),
201 Color::rgb(255, 160, 180),
202 Color::rgb(100, 220, 255),
203 ];
204 colors[index % colors.len()]
205 }
206
207 pub const fn tokens(&self) -> ThemeTokens {
208 ThemeTokens {
209 panel: self.surface,
210 text: self.text_primary,
211 dim: self.text_dim,
212 accent: self.accent,
213 success: self.success,
214 warning: self.warning,
215 error: self.error,
216 }
217 }
218}
219
220impl From<Theme> for ThemeTokens {
221 fn from(value: Theme) -> Self {
222 value.tokens()
223 }
224}
225
226impl From<&Theme> for ThemeTokens {
227 fn from(value: &Theme) -> Self {
228 value.tokens()
229 }
230}
231
232impl Default for Theme {
233 fn default() -> Self {
234 Self::DARK
235 }
236}