1use crate::css::Color;
6
7#[derive(Clone, Debug)]
9pub struct ColorScale {
10 pub c50: Color,
11 pub c100: Color,
12 pub c200: Color,
13 pub c300: Color,
14 pub c400: Color,
15 pub c500: Color,
16 pub c600: Color,
17 pub c700: Color,
18 pub c800: Color,
19 pub c900: Color,
20 pub c950: Color,
21}
22
23impl ColorScale {
24 pub fn new(
26 c50: Color,
27 c100: Color,
28 c200: Color,
29 c300: Color,
30 c400: Color,
31 c500: Color,
32 c600: Color,
33 c700: Color,
34 c800: Color,
35 c900: Color,
36 c950: Color,
37 ) -> Self {
38 Self {
39 c50,
40 c100,
41 c200,
42 c300,
43 c400,
44 c500,
45 c600,
46 c700,
47 c800,
48 c900,
49 c950,
50 }
51 }
52
53 pub fn get(&self, scale: u16) -> &Color {
55 match scale {
56 50 => &self.c50,
57 100 => &self.c100,
58 200 => &self.c200,
59 300 => &self.c300,
60 400 => &self.c400,
61 500 => &self.c500,
62 600 => &self.c600,
63 700 => &self.c700,
64 800 => &self.c800,
65 900 => &self.c900,
66 950 => &self.c950,
67 _ => &self.c500, }
69 }
70}
71
72#[derive(Clone, Debug)]
74pub struct SemanticColors {
75 pub success: Color,
77 pub error: Color,
79 pub warning: Color,
81 pub info: Color,
83}
84
85impl SemanticColors {
86 pub fn new(success: Color, error: Color, warning: Color, info: Color) -> Self {
88 Self {
89 success,
90 error,
91 warning,
92 info,
93 }
94 }
95
96 pub fn default() -> Self {
98 Self {
99 success: Color::hex("#10b981"), error: Color::hex("#ef4444"), warning: Color::hex("#f59e0b"), info: Color::hex("#3b82f6"), }
104 }
105}
106
107#[derive(Clone, Debug)]
109pub struct ColorTokens {
110 pub primary: ColorScale,
112 pub secondary: ColorScale,
114 pub semantic: SemanticColors,
116 pub background: BackgroundColors,
118 pub text: TextColors,
120}
121
122#[derive(Clone, Debug)]
124pub struct BackgroundColors {
125 pub base: Color,
126 pub elevated: Color,
127 pub overlay: Color,
128}
129
130#[derive(Clone, Debug)]
132pub struct TextColors {
133 pub primary: Color,
134 pub secondary: Color,
135 pub tertiary: Color,
136 pub inverse: Color,
137}
138
139impl ColorTokens {
140 pub fn new(
142 primary: ColorScale,
143 secondary: ColorScale,
144 semantic: SemanticColors,
145 background: BackgroundColors,
146 text: TextColors,
147 ) -> Self {
148 Self {
149 primary,
150 secondary,
151 semantic,
152 background,
153 text,
154 }
155 }
156
157 pub fn to_css_vars(&self) -> String {
159 let mut vars = String::new();
160
161 vars.push_str(" --color-primary-50: ");
163 vars.push_str(&self.primary.c50.to_css());
164 vars.push_str(";\n");
165 vars.push_str(" --color-primary-100: ");
166 vars.push_str(&self.primary.c100.to_css());
167 vars.push_str(";\n");
168 vars.push_str(" --color-primary-200: ");
169 vars.push_str(&self.primary.c200.to_css());
170 vars.push_str(";\n");
171 vars.push_str(" --color-primary-300: ");
172 vars.push_str(&self.primary.c300.to_css());
173 vars.push_str(";\n");
174 vars.push_str(" --color-primary-400: ");
175 vars.push_str(&self.primary.c400.to_css());
176 vars.push_str(";\n");
177 vars.push_str(" --color-primary-500: ");
178 vars.push_str(&self.primary.c500.to_css());
179 vars.push_str(";\n");
180 vars.push_str(" --color-primary-600: ");
181 vars.push_str(&self.primary.c600.to_css());
182 vars.push_str(";\n");
183 vars.push_str(" --color-primary-700: ");
184 vars.push_str(&self.primary.c700.to_css());
185 vars.push_str(";\n");
186 vars.push_str(" --color-primary-800: ");
187 vars.push_str(&self.primary.c800.to_css());
188 vars.push_str(";\n");
189 vars.push_str(" --color-primary-900: ");
190 vars.push_str(&self.primary.c900.to_css());
191 vars.push_str(";\n");
192 vars.push_str(" --color-primary-950: ");
193 vars.push_str(&self.primary.c950.to_css());
194 vars.push_str(";\n");
195
196 vars.push_str(" --color-success: ");
198 vars.push_str(&self.semantic.success.to_css());
199 vars.push_str(";\n");
200 vars.push_str(" --color-error: ");
201 vars.push_str(&self.semantic.error.to_css());
202 vars.push_str(";\n");
203 vars.push_str(" --color-warning: ");
204 vars.push_str(&self.semantic.warning.to_css());
205 vars.push_str(";\n");
206 vars.push_str(" --color-info: ");
207 vars.push_str(&self.semantic.info.to_css());
208 vars.push_str(";\n");
209
210 vars.push_str(" --color-bg-base: ");
212 vars.push_str(&self.background.base.to_css());
213 vars.push_str(";\n");
214 vars.push_str(" --color-bg-elevated: ");
215 vars.push_str(&self.background.elevated.to_css());
216 vars.push_str(";\n");
217 vars.push_str(" --color-bg-overlay: ");
218 vars.push_str(&self.background.overlay.to_css());
219 vars.push_str(";\n");
220
221 vars.push_str(" --color-text-primary: ");
223 vars.push_str(&self.text.primary.to_css());
224 vars.push_str(";\n");
225 vars.push_str(" --color-text-secondary: ");
226 vars.push_str(&self.text.secondary.to_css());
227 vars.push_str(";\n");
228 vars.push_str(" --color-text-tertiary: ");
229 vars.push_str(&self.text.tertiary.to_css());
230 vars.push_str(";\n");
231 vars.push_str(" --color-text-inverse: ");
232 vars.push_str(&self.text.inverse.to_css());
233 vars.push_str(";\n");
234
235 vars
236 }
237}
238
239impl Default for ColorTokens {
240 fn default() -> Self {
241 let primary = ColorScale::new(
243 Color::hex("#eff6ff"), Color::hex("#dbeafe"), Color::hex("#bfdbfe"), Color::hex("#93c5fd"), Color::hex("#60a5fa"), Color::hex("#3b82f6"), Color::hex("#2563eb"), Color::hex("#1d4ed8"), Color::hex("#1e40af"), Color::hex("#1e3a8a"), Color::hex("#172554"), );
255
256 let secondary = ColorScale::new(
258 Color::hex("#f9fafb"), Color::hex("#f3f4f6"), Color::hex("#e5e7eb"), Color::hex("#d1d5db"), Color::hex("#9ca3af"), Color::hex("#6b7280"), Color::hex("#4b5563"), Color::hex("#374151"), Color::hex("#1f2937"), Color::hex("#111827"), Color::hex("#030712"), );
270
271 Self {
272 primary,
273 secondary,
274 semantic: SemanticColors::default(),
275 background: BackgroundColors {
276 base: Color::hex("#ffffff"),
277 elevated: Color::hex("#f9fafb"),
278 overlay: Color::hex("rgba(0, 0, 0, 0.5)"),
279 },
280 text: TextColors {
281 primary: Color::hex("#111827"),
282 secondary: Color::hex("#6b7280"),
283 tertiary: Color::hex("#9ca3af"),
284 inverse: Color::hex("#ffffff"),
285 },
286 }
287 }
288}