windjammer-ui 0.3.6

Cross-platform UI framework for Windjammer (Web, Desktop, Mobile)
Documentation
// Theme System - Modern editor themes for Windjammer UI
// Supports dark/light modes and custom color palettes

use super::traits::Renderable

// Editor color palette
pub struct ColorPalette {
    // Backgrounds
    pub bg_primary: string,
    pub bg_secondary: string,
    pub bg_tertiary: string,
    pub bg_elevated: string,
    
    // Text
    pub text_primary: string,
    pub text_secondary: string,
    pub text_muted: string,
    
    // Accent colors
    pub accent_primary: string,
    pub accent_secondary: string,
    pub accent_success: string,
    pub accent_warning: string,
    pub accent_error: string,
    
    // Borders
    pub border_subtle: string,
    pub border_default: string,
    
    // Axis colors (for 3D editors)
    pub axis_x: string,
    pub axis_y: string,
    pub axis_z: string,
}

impl ColorPalette {
    // Default dark theme (inspired by modern game engines)
    pub fn dark() -> ColorPalette {
        ColorPalette {
            bg_primary: "#0a0a1a".to_string(),
            bg_secondary: "#16213e".to_string(),
            bg_tertiary: "#1a2744".to_string(),
            bg_elevated: "#1e2d4d".to_string(),
            text_primary: "#e0e0e0".to_string(),
            text_secondary: "#a0a0a0".to_string(),
            text_muted: "#666666".to_string(),
            accent_primary: "#e94560".to_string(),
            accent_secondary: "#0f3460".to_string(),
            accent_success: "#4ade80".to_string(),
            accent_warning: "#facc15".to_string(),
            accent_error: "#ef4444".to_string(),
            border_subtle: "rgba(255,255,255,0.05)".to_string(),
            border_default: "rgba(255,255,255,0.1)".to_string(),
            axis_x: "#e94560".to_string(),
            axis_y: "#4ade80".to_string(),
            axis_z: "#60a5fa".to_string(),
        }
    }
    
    // Light theme
    pub fn light() -> ColorPalette {
        ColorPalette {
            bg_primary: "#f5f5f5".to_string(),
            bg_secondary: "#ffffff".to_string(),
            bg_tertiary: "#fafafa".to_string(),
            bg_elevated: "#ffffff".to_string(),
            text_primary: "#1a1a2e".to_string(),
            text_secondary: "#666666".to_string(),
            text_muted: "#999999".to_string(),
            accent_primary: "#e94560".to_string(),
            accent_secondary: "#3b82f6".to_string(),
            accent_success: "#22c55e".to_string(),
            accent_warning: "#eab308".to_string(),
            accent_error: "#dc2626".to_string(),
            border_subtle: "rgba(0,0,0,0.05)".to_string(),
            border_default: "rgba(0,0,0,0.1)".to_string(),
            axis_x: "#dc2626".to_string(),
            axis_y: "#16a34a".to_string(),
            axis_z: "#2563eb".to_string(),
        }
    }
    
    // High contrast theme (accessibility)
    pub fn high_contrast() -> ColorPalette {
        ColorPalette {
            bg_primary: "#000000".to_string(),
            bg_secondary: "#1a1a1a".to_string(),
            bg_tertiary: "#2a2a2a".to_string(),
            bg_elevated: "#333333".to_string(),
            text_primary: "#ffffff".to_string(),
            text_secondary: "#cccccc".to_string(),
            text_muted: "#888888".to_string(),
            accent_primary: "#ffcc00".to_string(),
            accent_secondary: "#00ffcc".to_string(),
            accent_success: "#00ff00".to_string(),
            accent_warning: "#ffff00".to_string(),
            accent_error: "#ff0000".to_string(),
            border_subtle: "rgba(255,255,255,0.2)".to_string(),
            border_default: "rgba(255,255,255,0.4)".to_string(),
            axis_x: "#ff6666".to_string(),
            axis_y: "#66ff66".to_string(),
            axis_z: "#6666ff".to_string(),
        }
    }
    
    // Monokai-inspired theme
    pub fn monokai() -> ColorPalette {
        ColorPalette {
            bg_primary: "#272822".to_string(),
            bg_secondary: "#3e3d32".to_string(),
            bg_tertiary: "#49483e".to_string(),
            bg_elevated: "#75715e".to_string(),
            text_primary: "#f8f8f2".to_string(),
            text_secondary: "#a6a997".to_string(),
            text_muted: "#75715e".to_string(),
            accent_primary: "#f92672".to_string(),
            accent_secondary: "#66d9ef".to_string(),
            accent_success: "#a6e22e".to_string(),
            accent_warning: "#fd971f".to_string(),
            accent_error: "#f92672".to_string(),
            border_subtle: "rgba(255,255,255,0.05)".to_string(),
            border_default: "rgba(255,255,255,0.1)".to_string(),
            axis_x: "#f92672".to_string(),
            axis_y: "#a6e22e".to_string(),
            axis_z: "#66d9ef".to_string(),
        }
    }
    
    // Nord theme
    pub fn nord() -> ColorPalette {
        ColorPalette {
            bg_primary: "#2e3440".to_string(),
            bg_secondary: "#3b4252".to_string(),
            bg_tertiary: "#434c5e".to_string(),
            bg_elevated: "#4c566a".to_string(),
            text_primary: "#eceff4".to_string(),
            text_secondary: "#d8dee9".to_string(),
            text_muted: "#81a1c1".to_string(),
            accent_primary: "#88c0d0".to_string(),
            accent_secondary: "#81a1c1".to_string(),
            accent_success: "#a3be8c".to_string(),
            accent_warning: "#ebcb8b".to_string(),
            accent_error: "#bf616a".to_string(),
            border_subtle: "rgba(255,255,255,0.05)".to_string(),
            border_default: "rgba(255,255,255,0.1)".to_string(),
            axis_x: "#bf616a".to_string(),
            axis_y: "#a3be8c".to_string(),
            axis_z: "#5e81ac".to_string(),
        }
    }
}

// Full editor theme configuration
pub struct EditorTheme {
    pub name: string,
    pub palette: ColorPalette,
    pub font_family: string,
    pub font_size_base: i32,
    pub border_radius: i32,
    pub spacing_unit: i32,
    pub animation_duration: i32,
}

impl EditorTheme {
    pub fn default() -> EditorTheme {
        EditorTheme {
            name: "Windjammer Dark".to_string(),
            palette: ColorPalette::dark(),
            font_family: "'Inter', 'SF Pro', -apple-system, sans-serif".to_string(),
            font_size_base: 13,
            border_radius: 6,
            spacing_unit: 8,
            animation_duration: 150,
        }
    }
    
    pub fn light() -> EditorTheme {
        EditorTheme {
            name: "Windjammer Light".to_string(),
            palette: ColorPalette::light(),
            font_family: "'Inter', 'SF Pro', -apple-system, sans-serif".to_string(),
            font_size_base: 13,
            border_radius: 6,
            spacing_unit: 8,
            animation_duration: 150,
        }
    }
    
    pub fn monokai() -> EditorTheme {
        EditorTheme {
            name: "Monokai Pro".to_string(),
            palette: ColorPalette::monokai(),
            font_family: "'Fira Code', 'JetBrains Mono', monospace".to_string(),
            font_size_base: 13,
            border_radius: 4,
            spacing_unit: 8,
            animation_duration: 100,
        }
    }
    
    pub fn nord() -> EditorTheme {
        EditorTheme {
            name: "Nord".to_string(),
            palette: ColorPalette::nord(),
            font_family: "'Source Sans Pro', 'Nunito', sans-serif".to_string(),
            font_size_base: 14,
            border_radius: 8,
            spacing_unit: 10,
            animation_duration: 200,
        }
    }
}

impl Renderable for EditorTheme {
    pub fn render(self) -> string {
        let css = ":root { 
            --bg-primary: " + self.palette.bg_primary.as_str() + ";
            --bg-secondary: " + self.palette.bg_secondary.as_str() + ";
            --accent-primary: " + self.palette.accent_primary.as_str() + ";
            --text-primary: " + self.palette.text_primary.as_str() + ";
        }
        body {
            font-family: " + self.font_family.as_str() + ";
            color: var(--text-primary);
            background: var(--bg-primary);
        }"
        css
    }
}

// Theme switcher component
pub struct ThemeSwitcher {
    pub current_theme: string,
    pub themes: Vec<string>,
    pub on_change: string,
}

impl ThemeSwitcher {
    pub fn new() -> ThemeSwitcher {
        let mut themes = Vec::new()
        themes.push("dark".to_string())
        themes.push("light".to_string())
        themes.push("monokai".to_string())
        themes.push("nord".to_string())
        themes.push("high-contrast".to_string())
        
        ThemeSwitcher {
            current_theme: "dark".to_string(),
            themes,
            on_change: "".to_string(),
        }
    }
    
    pub fn on_change(self, handler: string) -> ThemeSwitcher {
        self.on_change = handler
        self
    }
}

impl Renderable for ThemeSwitcher {
    pub fn render(self) -> string {
        let mut options = "".to_string()
        for t in self.themes {
            let selected = if t.as_str() == self.current_theme.as_str() { "selected" } else { "" }
            options = options + format!("<option value='{}' {}>{}</option>", t, selected, t).as_str()
        }
        
        format!("
            <div class='theme-switcher'>
                <label>🎨 Theme</label>
                <select onchange='{}(this.value)'>
                    {}
                </select>
            </div>
        ", self.on_change, options)
    }
}