rustyle_css/
theme.rs

1//! Theme system for Rustyle
2//!
3//! Provides comprehensive theming with design token integration, multi-theme support,
4//! and system theme detection.
5
6use crate::css::Color;
7use crate::tokens::DesignTokens;
8
9/// Theme definition
10#[derive(Clone, Debug)]
11pub struct Theme {
12    /// Design tokens
13    pub tokens: DesignTokens,
14    /// Theme name
15    pub name: String,
16    /// Is dark theme
17    pub is_dark: bool,
18}
19
20impl Theme {
21    /// Create a new theme with design tokens
22    pub fn new(name: &str, tokens: DesignTokens, is_dark: bool) -> Self {
23        Self {
24            tokens,
25            name: name.to_string(),
26            is_dark,
27        }
28    }
29
30    /// Create a light theme with default tokens
31    pub fn light() -> Self {
32        Self {
33            tokens: DesignTokens::default(),
34            name: "light".to_string(),
35            is_dark: false,
36        }
37    }
38
39    /// Create a dark theme
40    pub fn dark() -> Self {
41        let mut tokens = DesignTokens::default();
42        // Adjust colors for dark theme
43        tokens.colors.background.base = Color::hex("#212529");
44        tokens.colors.background.elevated = Color::hex("#2d3238");
45        tokens.colors.text.primary = Color::hex("#ffffff");
46        tokens.colors.text.secondary = Color::hex("#adb5bd");
47
48        Self {
49            tokens,
50            name: "dark".to_string(),
51            is_dark: true,
52        }
53    }
54
55    /// Create a theme from custom design tokens
56    pub fn custom(name: &str, tokens: DesignTokens) -> Self {
57        Self {
58            tokens,
59            name: name.to_string(),
60            is_dark: false,
61        }
62    }
63
64    /// Convert theme to CSS variables
65    pub fn to_css_vars(&self) -> String {
66        self.tokens.to_css_vars()
67    }
68
69    /// Get theme name
70    pub fn name(&self) -> &str {
71        &self.name
72    }
73
74    /// Check if theme is dark
75    pub fn is_dark(&self) -> bool {
76        self.is_dark
77    }
78}
79
80/// Theme manager for multiple themes
81#[derive(Clone, Debug)]
82pub struct ThemeManager {
83    current: Theme,
84    themes: std::collections::HashMap<String, Theme>,
85}
86
87impl ThemeManager {
88    /// Create a new theme manager
89    pub fn new(initial_theme: Theme) -> Self {
90        let mut themes = std::collections::HashMap::new();
91        themes.insert(initial_theme.name.clone(), initial_theme.clone());
92
93        Self {
94            current: initial_theme,
95            themes,
96        }
97    }
98
99    /// Add a theme
100    pub fn add_theme(&mut self, theme: Theme) {
101        self.themes.insert(theme.name.clone(), theme);
102    }
103
104    /// Switch to a theme by name
105    pub fn switch_to(&mut self, name: &str) -> Option<&Theme> {
106        if let Some(theme) = self.themes.get(name) {
107            self.current = theme.clone();
108            Some(&self.current)
109        } else {
110            None
111        }
112    }
113
114    /// Get current theme
115    pub fn current(&self) -> &Theme {
116        &self.current
117    }
118
119    /// Get all theme names
120    pub fn theme_names(&self) -> Vec<&String> {
121        self.themes.keys().collect()
122    }
123}
124
125impl Default for ThemeManager {
126    fn default() -> Self {
127        Self::new(Theme::light())
128    }
129}
130
131/// Apply a theme (injects CSS variables)
132pub fn apply_theme(theme: &Theme) {
133    let css = theme.to_css_vars();
134    crate::register_global_style(&css);
135
136    #[cfg(all(feature = "csr", target_arch = "wasm32"))]
137    {
138        crate::csr::inject_styles_csr(&css);
139    }
140}
141
142/// Apply theme with transition
143pub fn apply_theme_with_transition(theme: &Theme, duration: &str) {
144    let css = format!(
145        r#"
146        :root {{
147            transition: background-color {}, color {}, border-color {};
148        }}
149        {}
150        "#,
151        duration,
152        duration,
153        duration,
154        theme.to_css_vars()
155    );
156
157    crate::register_global_style(&css);
158
159    #[cfg(all(feature = "csr", target_arch = "wasm32"))]
160    {
161        crate::csr::inject_styles_csr(&css);
162    }
163}
164
165/// System theme detection CSS
166pub fn system_theme_detection() -> String {
167    r#"
168    @media (prefers-color-scheme: dark) {
169        :root {
170            color-scheme: dark;
171        }
172    }
173    
174    @media (prefers-color-scheme: light) {
175        :root {
176            color-scheme: light;
177        }
178    }
179    "#
180    .to_string()
181}
182
183/// Register system theme detection
184pub fn register_system_theme() {
185    let css = system_theme_detection();
186    crate::register_global_style(&css);
187
188    #[cfg(all(feature = "csr", target_arch = "wasm32"))]
189    {
190        crate::csr::inject_styles_csr(&css);
191    }
192}