use crate::core::{Color, Font};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Theme {
pub name: String,
pub colors: Colors,
pub fonts: Fonts,
pub spacing: Spacing,
pub borders: Borders,
pub overrides: ThemeOverrides,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Colors {
pub background: Color,
pub foreground: Color,
pub primary: Color,
pub secondary: Color,
pub accent: Color,
pub error: Color,
pub warning: Color,
pub success: Color,
pub disabled: Color,
#[serde(default = "default_info_color")]
pub info: Color,
}
const fn default_info_color() -> Color {
Color::INFO
}
impl Color {
pub fn from_hex(hex: &str) -> Result<Self, String> {
Self::parse_hex(hex).ok_or_else(|| format!("Invalid hex color string: '{}'", hex))
}
pub fn to_hex(&self) -> String {
self.to_hex_rgba()
}
pub fn dark_variant(&self, factor: f32) -> Self {
let f = factor.clamp(0.0, 1.0);
Self::rgba(
(self.r as f32 * (1.0 - f)).round().clamp(0.0, 255.0) as u8,
(self.g as f32 * (1.0 - f)).round().clamp(0.0, 255.0) as u8,
(self.b as f32 * (1.0 - f)).round().clamp(0.0, 255.0) as u8,
self.a,
)
}
pub fn light_variant(&self, factor: f32) -> Self {
let f = factor.clamp(0.0, 1.0);
Self::rgba(
(self.r as f32 + (255.0 - self.r as f32) * f).round().clamp(0.0, 255.0) as u8,
(self.g as f32 + (255.0 - self.g as f32) * f).round().clamp(0.0, 255.0) as u8,
(self.b as f32 + (255.0 - self.b as f32) * f).round().clamp(0.0, 255.0) as u8,
self.a,
)
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Fonts {
pub regular: Font,
pub bold: Font,
pub italic: Font,
pub monospace: Font,
#[serde(default = "default_caption_font")]
pub caption: Font,
#[serde(default = "default_body_font")]
pub body: Font,
#[serde(default = "default_title_font")]
pub title: Font,
#[serde(default = "default_headline_font")]
pub headline: Font,
#[serde(default = "default_display_font")]
pub display: Font,
}
fn default_caption_font() -> Font {
Font::simple("Arial", 11.0)
}
fn default_body_font() -> Font {
Font::simple("Arial", 14.0)
}
fn default_title_font() -> Font {
Font::bold("Arial", 16.0)
}
fn default_headline_font() -> Font {
Font::bold("Arial", 20.0)
}
fn default_display_font() -> Font {
Font::bold("Arial", 28.0)
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Spacing {
pub small: u32,
pub medium: u32,
pub large: u32,
pub extra_large: u32,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Borders {
pub width: u32,
pub radius: u32,
pub shadow: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThemeOverrides {
pub styles: HashMap<String, ThemeStyleToken>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThemeStyleToken {
pub background: Option<Color>,
pub foreground: Option<Color>,
pub border: Option<Color>,
pub border_width: Option<u32>,
pub radius: Option<u32>,
}