rustyle_css/tokens/
color.rs

1//! Color token system
2//!
3//! Provides a comprehensive color system with primary, secondary, and semantic colors.
4
5use crate::css::Color;
6
7/// Color scale from 50 (lightest) to 950 (darkest)
8#[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    /// Create a new color scale
25    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    /// Get a color by scale value
54    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, // Default to middle
68        }
69    }
70}
71
72/// Semantic colors for UI states
73#[derive(Clone, Debug)]
74pub struct SemanticColors {
75    /// Success state color
76    pub success: Color,
77    /// Error state color
78    pub error: Color,
79    /// Warning state color
80    pub warning: Color,
81    /// Info state color
82    pub info: Color,
83}
84
85impl SemanticColors {
86    /// Create new semantic colors
87    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    /// Default semantic colors
97    pub fn default() -> Self {
98        Self {
99            success: Color::hex("#10b981"), // Green
100            error: Color::hex("#ef4444"),   // Red
101            warning: Color::hex("#f59e0b"), // Amber
102            info: Color::hex("#3b82f6"),    // Blue
103        }
104    }
105}
106
107/// Comprehensive color token system
108#[derive(Clone, Debug)]
109pub struct ColorTokens {
110    /// Primary color scale
111    pub primary: ColorScale,
112    /// Secondary color scale
113    pub secondary: ColorScale,
114    /// Semantic colors
115    pub semantic: SemanticColors,
116    /// Background colors
117    pub background: BackgroundColors,
118    /// Text colors
119    pub text: TextColors,
120}
121
122/// Background color tokens
123#[derive(Clone, Debug)]
124pub struct BackgroundColors {
125    pub base: Color,
126    pub elevated: Color,
127    pub overlay: Color,
128}
129
130/// Text color tokens
131#[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    /// Create new color tokens
141    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    /// Convert color tokens to CSS custom properties
158    pub fn to_css_vars(&self) -> String {
159        let mut vars = String::new();
160
161        // Primary scale
162        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        // Semantic colors
197        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        // Background colors
211        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        // Text colors
222        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        // Default blue primary scale
242        let primary = ColorScale::new(
243            Color::hex("#eff6ff"), // 50
244            Color::hex("#dbeafe"), // 100
245            Color::hex("#bfdbfe"), // 200
246            Color::hex("#93c5fd"), // 300
247            Color::hex("#60a5fa"), // 400
248            Color::hex("#3b82f6"), // 500
249            Color::hex("#2563eb"), // 600
250            Color::hex("#1d4ed8"), // 700
251            Color::hex("#1e40af"), // 800
252            Color::hex("#1e3a8a"), // 900
253            Color::hex("#172554"), // 950
254        );
255
256        // Default gray secondary scale
257        let secondary = ColorScale::new(
258            Color::hex("#f9fafb"), // 50
259            Color::hex("#f3f4f6"), // 100
260            Color::hex("#e5e7eb"), // 200
261            Color::hex("#d1d5db"), // 300
262            Color::hex("#9ca3af"), // 400
263            Color::hex("#6b7280"), // 500
264            Color::hex("#4b5563"), // 600
265            Color::hex("#374151"), // 700
266            Color::hex("#1f2937"), // 800
267            Color::hex("#111827"), // 900
268            Color::hex("#030712"), // 950
269        );
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}