use crate::geometry::Color;
use crate::view::paint::ShadowSpec;
#[derive(Debug, Clone, Copy)]
pub struct TextTokens {
pub regular_default: Color,
pub subtle_default: Color,
pub link_default: Color,
pub link_hover: Color,
pub brand_default: Color,
pub brand_hover: Color,
pub on_brand_default: Color,
}
#[derive(Debug, Clone, Copy)]
pub struct BackgroundTokens {
pub primary_default: Color,
pub secondary_default: Color,
pub tertiary_default: Color,
pub brand_default: Color,
pub brand_hover: Color,
pub brand_clicked: Color,
pub disabled_default: Color,
}
#[derive(Debug, Clone, Copy)]
pub struct BorderTokens {
pub default: Color,
pub strong: Color,
}
#[derive(Debug, Clone, Copy)]
pub struct RadiusTokens {
pub small: f32,
pub medium: f32,
pub large: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct SpacerTokens {
pub xs: f32,
pub sm: f32,
pub md: f32,
pub lg: f32,
pub xl: f32,
pub x2l: f32,
pub x3l: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct FontTokens {
pub xs: f64,
pub sm: f64,
pub md: f64,
pub lg: f64,
pub xl: f64,
pub x2l: f64,
pub x3l: f64,
pub x4l: f64,
}
#[derive(Debug, Clone, Copy)]
pub struct ShadowTokens {
pub sm: ShadowSpec,
pub md: ShadowSpec,
pub lg: ShadowSpec,
}
#[derive(Debug, Clone, Copy)]
pub struct StatusTokens {
pub danger: Color,
pub danger_bg: Color,
pub success: Color,
pub success_bg: Color,
pub warning: Color,
pub warning_bg: Color,
pub info: Color,
pub info_bg: Color,
}
#[derive(Debug, Clone, Copy)]
pub struct Theme {
pub text: TextTokens,
pub background: BackgroundTokens,
pub border: BorderTokens,
pub radius: RadiusTokens,
pub spacer: SpacerTokens,
pub font: FontTokens,
pub shadow: ShadowTokens,
pub status: StatusTokens,
}
impl Theme {
pub fn light() -> Self {
let shadow_color = Color::rgba(3, 3, 3, 26); Theme {
text: TextTokens {
regular_default: Color::from_hex("#151515"),
subtle_default: Color::from_hex("#6a6e73"),
link_default: Color::from_hex("#0066cc"),
link_hover: Color::from_hex("#004d99"),
brand_default: Color::from_hex("#0066cc"),
brand_hover: Color::from_hex("#004d99"),
on_brand_default: Color::WHITE,
},
background: BackgroundTokens {
primary_default: Color::from_hex("#ffffff"),
secondary_default: Color::from_hex("#f2f2f2"),
tertiary_default: Color::from_hex("#e0e0e0"),
brand_default: Color::from_hex("#0066cc"),
brand_hover: Color::from_hex("#004d99"),
brand_clicked: Color::from_hex("#004d99"),
disabled_default: Color::from_hex("#d2d2d2"),
},
border: BorderTokens {
default: Color::from_hex("#e0e0e0"),
strong: Color::from_hex("#c7c7c7"),
},
radius: RadiusTokens {
small: 3.0,
medium: 6.0,
large: 12.0,
},
spacer: SpacerTokens {
xs: 4.0,
sm: 8.0,
md: 16.0,
lg: 24.0,
xl: 32.0,
x2l: 40.0,
x3l: 48.0,
},
font: FontTokens {
xs: 12.0,
sm: 14.0,
md: 16.0,
lg: 18.0,
xl: 24.0,
x2l: 32.0,
x3l: 40.0,
x4l: 48.0,
},
shadow: ShadowTokens {
sm: ShadowSpec {
offset_x: 0.0,
offset_y: 1.0,
blur: 2.0,
spread: 0.0,
color: shadow_color,
},
md: ShadowSpec {
offset_x: 0.0,
offset_y: 4.0,
blur: 8.0,
spread: 0.0,
color: shadow_color,
},
lg: ShadowSpec {
offset_x: 0.0,
offset_y: 21.0,
blur: 32.0,
spread: -11.0,
color: Color::rgba(3, 3, 3, 30),
},
},
status: StatusTokens {
danger: Color::from_hex("#c9190b"),
danger_bg: Color::from_hex("#faeae8"),
success: Color::from_hex("#3e8635"),
success_bg: Color::from_hex("#e6f4ea"),
warning: Color::from_hex("#f0ab00"),
warning_bg: Color::from_hex("#fdf7d0"),
info: Color::from_hex("#0066cc"),
info_bg: Color::from_hex("#e7f1fa"),
},
}
}
pub fn dark() -> Self {
let mut t = Self::light();
t.text.regular_default = Color::from_hex("#f0f0f0");
t.text.subtle_default = Color::from_hex("#a3a3a3");
t.text.on_brand_default = Color::WHITE;
t.background.primary_default = Color::from_hex("#1b1d23");
t.background.secondary_default = Color::from_hex("#151515");
t.background.tertiary_default = Color::from_hex("#383838");
t.background.disabled_default = Color::from_hex("#383838");
t.border.default = Color::from_hex("#383838");
t.border.strong = Color::from_hex("#6a6a6a");
let dk = Color::rgba(0, 0, 0, 70);
t.shadow.sm = ShadowSpec {
color: dk,
..t.shadow.sm
};
t.shadow.md = ShadowSpec {
color: dk,
..t.shadow.md
};
t.shadow.lg = ShadowSpec {
color: dk,
..t.shadow.lg
};
t
}
}
use std::cell::RefCell;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Mode {
Light,
Dark,
}
thread_local! {
static THEME: RefCell<Theme> = RefCell::new(Theme::light());
static MODE: RefCell<Mode> = const { RefCell::new(Mode::Light) };
}
pub fn current() -> Theme {
THEME.with(|t| *t.borrow())
}
pub fn set(theme: Theme) {
THEME.with(|t| *t.borrow_mut() = theme);
}
pub fn set_mode(mode: Mode) {
MODE.with(|m| *m.borrow_mut() = mode);
set(match mode {
Mode::Light => Theme::light(),
Mode::Dark => Theme::dark(),
});
}