pub mod control;
pub use control::{ControlMetrics, ControlScale, ControlSize, TrackMetrics};
use gpui::{hsla, px, App, BoxShadow, Global, Hsla, Pixels, SharedString};
use std::sync::Arc;
pub const FOCUS_RING_WIDTH: Pixels = px(2.);
pub fn focus_ring(color: Hsla) -> Vec<BoxShadow> {
vec![BoxShadow::new(px(0.), px(0.), color).spread_radius(FOCUS_RING_WIDTH)]
}
pub trait Themeable {
fn fg(&self) -> Hsla;
fn bg(&self) -> Hsla;
fn surface(&self) -> Hsla;
fn border(&self) -> Hsla;
fn accent(&self) -> Hsla;
fn fg_muted(&self) -> Hsla {
self.fg().opacity(0.7)
}
fn fg_disabled(&self) -> Hsla {
self.fg().opacity(0.4)
}
fn surface_secondary(&self) -> Hsla {
self.surface()
}
fn surface_tertiary(&self) -> Hsla {
self.surface_secondary()
}
fn border_secondary(&self) -> Hsla {
self.border()
}
fn border_subtle(&self) -> Hsla {
self.border().opacity(0.5)
}
fn outline(&self) -> Hsla {
self.accent()
}
fn accent_bg(&self) -> Hsla {
self.accent().opacity(0.15)
}
fn accent_bg_hover(&self) -> Hsla {
self.accent().opacity(0.25)
}
fn info(&self) -> Hsla {
hsla(210.0 / 360.0, 0.7, 0.5, 1.0)
}
fn success(&self) -> Hsla {
hsla(142.0 / 360.0, 0.7, 0.4, 1.0)
}
fn warning(&self) -> Hsla {
hsla(38.0 / 360.0, 0.9, 0.5, 1.0)
}
fn danger(&self) -> Hsla {
hsla(0.0, 0.7, 0.5, 1.0)
}
fn selection(&self) -> Hsla {
self.accent().opacity(0.3)
}
fn placeholder(&self) -> Hsla {
self.fg().opacity(0.5)
}
fn overlay(&self) -> Hsla {
hsla(0.0, 0.0, 0.0, 0.6)
}
fn button_bg(&self) -> Hsla {
self.surface()
}
fn button_bg_hover(&self) -> Hsla {
self.surface_secondary()
}
fn button_bg_active(&self) -> Hsla {
self.surface_tertiary()
}
fn button_border(&self) -> Hsla {
self.border()
}
fn destructive_bg(&self) -> Hsla {
self.danger()
}
fn destructive_bg_hover(&self) -> Hsla {
let base = self.destructive_bg();
hsla(base.h, base.s, (base.l + 0.08).min(1.0), base.a)
}
fn destructive_bg_active(&self) -> Hsla {
let base = self.destructive_bg();
hsla(base.h, base.s, (base.l - 0.08).max(0.0), base.a)
}
fn destructive_fg(&self) -> Hsla {
let bg = self.destructive_bg();
if bg.l > 0.6 {
hsla(0.0, 0.0, 0.0, 1.0)
} else {
hsla(0.0, 0.0, 1.0, 1.0)
}
}
fn input_bg(&self) -> Hsla {
self.surface()
}
fn input_border(&self) -> Hsla {
self.border()
}
fn input_border_hover(&self) -> Hsla {
self.border_secondary()
}
fn input_border_focused(&self) -> Hsla {
self.accent()
}
fn input_text(&self) -> Hsla {
self.fg()
}
fn input_placeholder(&self) -> Hsla {
self.placeholder()
}
fn input_selection(&self) -> Hsla {
self.selection()
}
fn input_cursor(&self) -> Hsla {
self.accent()
}
fn badge_blue(&self) -> Hsla {
self.info()
}
fn badge_gold(&self) -> Hsla {
self.warning()
}
fn badge_red(&self) -> Hsla {
self.danger()
}
fn badge_green(&self) -> Hsla {
self.success()
}
fn badge_teal(&self) -> Hsla {
hsla(180.0 / 360.0, 0.55, 0.45, 1.0)
}
fn badge_amber(&self) -> Hsla {
hsla(30.0 / 360.0, 0.7, 0.50, 1.0)
}
fn badge_gray(&self) -> Hsla {
self.fg_muted()
}
fn control_scale(&self) -> ControlScale {
ControlScale::default()
}
fn control(&self, size: ControlSize) -> ControlMetrics {
self.control_scale().metrics(size)
}
}
pub fn init(cx: &mut App) {
cx.set_global(GlobalTheme::default());
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ThemeVariant {
#[default]
Dark,
Light,
}
#[derive(Debug, Clone)]
pub struct Theme {
pub name: SharedString,
pub variant: ThemeVariant,
pub fg_color: Hsla,
pub bg_color: Hsla,
pub surface_color: Hsla,
pub border_color: Hsla,
pub accent_color: Hsla,
pub fg_muted_color: Option<Hsla>,
pub fg_disabled_color: Option<Hsla>,
pub surface_secondary_color: Option<Hsla>,
pub surface_tertiary_color: Option<Hsla>,
pub border_secondary_color: Option<Hsla>,
pub border_subtle_color: Option<Hsla>,
pub outline_color: Option<Hsla>,
pub accent_bg_color: Option<Hsla>,
pub accent_bg_hover_color: Option<Hsla>,
pub info_color: Option<Hsla>,
pub success_color: Option<Hsla>,
pub warning_color: Option<Hsla>,
pub danger_color: Option<Hsla>,
pub selection_color: Option<Hsla>,
pub button_bg_color: Option<Hsla>,
pub button_bg_hover_color: Option<Hsla>,
pub button_bg_active_color: Option<Hsla>,
pub button_border_color: Option<Hsla>,
pub input_bg_color: Option<Hsla>,
pub input_border_color: Option<Hsla>,
pub input_border_hover_color: Option<Hsla>,
pub input_border_focused_color: Option<Hsla>,
pub input_text_color: Option<Hsla>,
pub input_placeholder_color: Option<Hsla>,
pub input_selection_color: Option<Hsla>,
pub input_cursor_color: Option<Hsla>,
pub overlay_color: Option<Hsla>,
pub badge_blue_color: Option<Hsla>,
pub badge_gold_color: Option<Hsla>,
pub badge_red_color: Option<Hsla>,
pub badge_green_color: Option<Hsla>,
pub badge_teal_color: Option<Hsla>,
pub badge_amber_color: Option<Hsla>,
pub badge_gray_color: Option<Hsla>,
pub controls: ControlScale,
}
impl Themeable for Theme {
fn fg(&self) -> Hsla {
self.fg_color
}
fn bg(&self) -> Hsla {
self.bg_color
}
fn surface(&self) -> Hsla {
self.surface_color
}
fn border(&self) -> Hsla {
self.border_color
}
fn accent(&self) -> Hsla {
self.accent_color
}
fn fg_muted(&self) -> Hsla {
self.fg_muted_color
.unwrap_or_else(|| self.fg().opacity(0.7))
}
fn fg_disabled(&self) -> Hsla {
self.fg_disabled_color
.unwrap_or_else(|| self.fg().opacity(0.4))
}
fn surface_secondary(&self) -> Hsla {
self.surface_secondary_color
.unwrap_or_else(|| self.surface())
}
fn surface_tertiary(&self) -> Hsla {
self.surface_tertiary_color
.unwrap_or_else(|| self.surface_secondary())
}
fn border_secondary(&self) -> Hsla {
self.border_secondary_color.unwrap_or_else(|| self.border())
}
fn border_subtle(&self) -> Hsla {
self.border_subtle_color
.unwrap_or_else(|| self.border().opacity(0.5))
}
fn outline(&self) -> Hsla {
self.outline_color.unwrap_or_else(|| self.accent())
}
fn accent_bg(&self) -> Hsla {
self.accent_bg_color
.unwrap_or_else(|| self.accent().opacity(0.15))
}
fn accent_bg_hover(&self) -> Hsla {
self.accent_bg_hover_color
.unwrap_or_else(|| self.accent().opacity(0.25))
}
fn info(&self) -> Hsla {
self.info_color
.unwrap_or_else(|| hsla(210.0 / 360.0, 0.7, 0.5, 1.0))
}
fn success(&self) -> Hsla {
self.success_color
.unwrap_or_else(|| hsla(142.0 / 360.0, 0.7, 0.4, 1.0))
}
fn warning(&self) -> Hsla {
self.warning_color
.unwrap_or_else(|| hsla(38.0 / 360.0, 0.9, 0.5, 1.0))
}
fn danger(&self) -> Hsla {
self.danger_color
.unwrap_or_else(|| hsla(0.0, 0.7, 0.5, 1.0))
}
fn selection(&self) -> Hsla {
self.selection_color
.unwrap_or_else(|| self.accent().opacity(0.3))
}
fn placeholder(&self) -> Hsla {
self.fg().opacity(0.5)
}
fn button_bg(&self) -> Hsla {
self.button_bg_color.unwrap_or_else(|| self.surface())
}
fn button_bg_hover(&self) -> Hsla {
self.button_bg_hover_color
.unwrap_or_else(|| self.surface_secondary())
}
fn button_bg_active(&self) -> Hsla {
self.button_bg_active_color
.unwrap_or_else(|| self.surface_tertiary())
}
fn button_border(&self) -> Hsla {
self.button_border_color.unwrap_or_else(|| self.border())
}
fn input_bg(&self) -> Hsla {
self.input_bg_color.unwrap_or_else(|| self.surface())
}
fn input_border(&self) -> Hsla {
self.input_border_color.unwrap_or_else(|| self.border())
}
fn input_border_hover(&self) -> Hsla {
self.input_border_hover_color
.unwrap_or_else(|| self.border_secondary())
}
fn input_border_focused(&self) -> Hsla {
self.input_border_focused_color
.unwrap_or_else(|| self.accent())
}
fn input_text(&self) -> Hsla {
self.input_text_color.unwrap_or_else(|| self.fg())
}
fn input_placeholder(&self) -> Hsla {
self.input_placeholder_color
.unwrap_or_else(|| self.placeholder())
}
fn input_selection(&self) -> Hsla {
self.input_selection_color
.unwrap_or_else(|| self.selection())
}
fn input_cursor(&self) -> Hsla {
self.input_cursor_color.unwrap_or_else(|| self.accent())
}
fn overlay(&self) -> Hsla {
self.overlay_color
.unwrap_or_else(|| hsla(0.0, 0.0, 0.0, 0.6))
}
fn badge_blue(&self) -> Hsla {
self.badge_blue_color.unwrap_or_else(|| self.info())
}
fn badge_gold(&self) -> Hsla {
self.badge_gold_color.unwrap_or_else(|| self.warning())
}
fn badge_red(&self) -> Hsla {
self.badge_red_color.unwrap_or_else(|| self.danger())
}
fn badge_green(&self) -> Hsla {
self.badge_green_color.unwrap_or_else(|| self.success())
}
fn badge_teal(&self) -> Hsla {
self.badge_teal_color
.unwrap_or_else(|| hsla(180.0 / 360.0, 0.55, 0.45, 1.0))
}
fn badge_amber(&self) -> Hsla {
self.badge_amber_color
.unwrap_or_else(|| hsla(30.0 / 360.0, 0.7, 0.50, 1.0))
}
fn badge_gray(&self) -> Hsla {
self.badge_gray_color.unwrap_or_else(|| self.fg_muted())
}
fn control_scale(&self) -> ControlScale {
self.controls
}
}
impl Theme {
pub fn new(
name: impl Into<SharedString>,
variant: ThemeVariant,
fg: Hsla,
bg: Hsla,
surface: Hsla,
border: Hsla,
accent: Hsla,
) -> Self {
Theme {
name: name.into(),
variant,
fg_color: fg,
bg_color: bg,
surface_color: surface,
border_color: border,
accent_color: accent,
fg_muted_color: None,
fg_disabled_color: None,
surface_secondary_color: None,
surface_tertiary_color: None,
border_secondary_color: None,
border_subtle_color: None,
outline_color: None,
accent_bg_color: None,
accent_bg_hover_color: None,
info_color: None,
success_color: None,
warning_color: None,
danger_color: None,
selection_color: None,
button_bg_color: None,
button_bg_hover_color: None,
button_bg_active_color: None,
button_border_color: None,
input_bg_color: None,
input_border_color: None,
input_border_hover_color: None,
input_border_focused_color: None,
input_text_color: None,
input_placeholder_color: None,
input_selection_color: None,
input_cursor_color: None,
overlay_color: None,
badge_blue_color: None,
badge_gold_color: None,
badge_red_color: None,
badge_green_color: None,
badge_teal_color: None,
badge_amber_color: None,
badge_gray_color: None,
controls: ControlScale::default(),
}
}
pub fn gruvbox_dark() -> Self {
let mut theme = Theme::new(
"Gruvbox Dark",
ThemeVariant::Dark,
parse_hex("#ebdbb2"), parse_hex("#282828"), parse_hex("#3c3836"), parse_hex("#504945"), parse_hex("#8ec07c"), );
theme.fg_muted_color = Some(parse_hex("#a89984"));
theme.fg_disabled_color = Some(parse_hex("#7c6f64"));
theme.surface_secondary_color = Some(parse_hex("#504945"));
theme.surface_tertiary_color = Some(parse_hex("#665c54"));
theme.border_secondary_color = Some(parse_hex("#7c6f64"));
theme.border_subtle_color = Some(parse_hex("#3c3836"));
theme.outline_color = Some(parse_hex("#458588"));
theme.info_color = Some(parse_hex("#458588"));
theme.success_color = Some(parse_hex("#b8bb26"));
theme.warning_color = Some(parse_hex("#fabd2f"));
theme.danger_color = Some(parse_hex("#fb4934"));
theme.selection_color = Some(hsla(55.0 / 360.0, 0.56, 0.64, 0.25));
theme.button_bg_color = Some(parse_hex("#504945"));
theme.button_bg_hover_color = Some(parse_hex("#665c54"));
theme.button_bg_active_color = Some(parse_hex("#7c6f64"));
theme.button_border_color = Some(parse_hex("#7c6f64"));
theme.input_border_hover_color = Some(parse_hex("#665c54"));
theme
}
pub fn gruvbox_light() -> Self {
let mut theme = Theme::new(
"Gruvbox Light",
ThemeVariant::Light,
parse_hex("#3c3836"), parse_hex("#fbf1c7"), parse_hex("#ebdbb2"), parse_hex("#d5c4a1"), parse_hex("#427b58"), );
theme.fg_muted_color = Some(parse_hex("#665c54"));
theme.fg_disabled_color = Some(parse_hex("#a89984"));
theme.surface_secondary_color = Some(parse_hex("#d5c4a1"));
theme.surface_tertiary_color = Some(parse_hex("#bdae93"));
theme.border_secondary_color = Some(parse_hex("#a89984"));
theme.border_subtle_color = Some(parse_hex("#ebdbb2"));
theme.outline_color = Some(parse_hex("#076678"));
theme.info_color = Some(parse_hex("#076678"));
theme.success_color = Some(parse_hex("#79740e"));
theme.warning_color = Some(parse_hex("#b57614"));
theme.danger_color = Some(parse_hex("#cc241d"));
theme.selection_color = Some(hsla(48.0 / 360.0, 0.87, 0.61, 0.15));
theme.button_bg_color = Some(parse_hex("#ebdbb2"));
theme.button_bg_hover_color = Some(parse_hex("#d5c4a1"));
theme.button_bg_active_color = Some(parse_hex("#bdae93"));
theme.button_border_color = Some(parse_hex("#a89984"));
theme.input_border_hover_color = Some(parse_hex("#bdae93"));
theme
}
pub fn catppuccin_latte() -> Self {
let mut theme = Theme::new(
"Catppuccin Latte",
ThemeVariant::Light,
parse_hex("#4c4f69"), parse_hex("#eff1f5"), parse_hex("#e6e9ef"), parse_hex("#ccd0da"), parse_hex("#8839ef"), );
theme.fg_muted_color = Some(parse_hex("#6c6f85"));
theme.fg_disabled_color = Some(parse_hex("#9ca0b0"));
theme.surface_secondary_color = Some(parse_hex("#ccd0da"));
theme.surface_tertiary_color = Some(parse_hex("#bcc0cc"));
theme.border_secondary_color = Some(parse_hex("#acb0be"));
theme.border_subtle_color = Some(parse_hex("#e6e9ef"));
theme.info_color = Some(parse_hex("#1e66f5"));
theme.success_color = Some(parse_hex("#40a02b"));
theme.warning_color = Some(parse_hex("#df8e1d"));
theme.danger_color = Some(parse_hex("#d20f39"));
theme.button_bg_color = Some(parse_hex("#ccd0da"));
theme.button_bg_hover_color = Some(parse_hex("#bcc0cc"));
theme.button_bg_active_color = Some(parse_hex("#acb0be"));
theme.button_border_color = Some(parse_hex("#acb0be"));
theme.input_border_hover_color = Some(parse_hex("#acb0be"));
theme.badge_blue_color = Some(parse_hex("#1e66f5"));
theme.badge_gold_color = Some(parse_hex("#df8e1d"));
theme.badge_red_color = Some(parse_hex("#d20f39"));
theme.badge_green_color = Some(parse_hex("#40a02b"));
theme.badge_teal_color = Some(parse_hex("#179299"));
theme.badge_amber_color = Some(parse_hex("#fe640b"));
theme.badge_gray_color = Some(parse_hex("#6c6f85"));
theme
}
pub fn catppuccin_frappe() -> Self {
let mut theme = Theme::new(
"Catppuccin Frappé",
ThemeVariant::Dark,
parse_hex("#c6d0f5"), parse_hex("#303446"), parse_hex("#292c3c"), parse_hex("#414559"), parse_hex("#ca9ee6"), );
theme.fg_muted_color = Some(parse_hex("#a5adce"));
theme.fg_disabled_color = Some(parse_hex("#838ba7"));
theme.surface_secondary_color = Some(parse_hex("#51576d"));
theme.surface_tertiary_color = Some(parse_hex("#626880"));
theme.border_secondary_color = Some(parse_hex("#626880"));
theme.border_subtle_color = Some(parse_hex("#292c3c"));
theme.info_color = Some(parse_hex("#8caaee"));
theme.success_color = Some(parse_hex("#a6d189"));
theme.warning_color = Some(parse_hex("#e5c890"));
theme.danger_color = Some(parse_hex("#e78284"));
theme.button_bg_color = Some(parse_hex("#414559"));
theme.button_bg_hover_color = Some(parse_hex("#51576d"));
theme.button_bg_active_color = Some(parse_hex("#626880"));
theme.button_border_color = Some(parse_hex("#626880"));
theme.input_border_hover_color = Some(parse_hex("#51576d"));
theme.badge_blue_color = Some(parse_hex("#8caaee"));
theme.badge_gold_color = Some(parse_hex("#e5c890"));
theme.badge_red_color = Some(parse_hex("#e78284"));
theme.badge_green_color = Some(parse_hex("#a6d189"));
theme.badge_teal_color = Some(parse_hex("#81c8be"));
theme.badge_amber_color = Some(parse_hex("#ef9f76"));
theme.badge_gray_color = Some(parse_hex("#a5adce"));
theme
}
pub fn catppuccin_macchiato() -> Self {
let mut theme = Theme::new(
"Catppuccin Macchiato",
ThemeVariant::Dark,
parse_hex("#cad3f5"), parse_hex("#24273a"), parse_hex("#1e2030"), parse_hex("#363a4f"), parse_hex("#c6a0f6"), );
theme.fg_muted_color = Some(parse_hex("#a5adcb"));
theme.fg_disabled_color = Some(parse_hex("#8087a2"));
theme.surface_secondary_color = Some(parse_hex("#494d64"));
theme.surface_tertiary_color = Some(parse_hex("#5b6078"));
theme.border_secondary_color = Some(parse_hex("#5b6078"));
theme.border_subtle_color = Some(parse_hex("#1e2030"));
theme.info_color = Some(parse_hex("#8aadf4"));
theme.success_color = Some(parse_hex("#a6da95"));
theme.warning_color = Some(parse_hex("#eed49f"));
theme.danger_color = Some(parse_hex("#ed8796"));
theme.button_bg_color = Some(parse_hex("#363a4f"));
theme.button_bg_hover_color = Some(parse_hex("#494d64"));
theme.button_bg_active_color = Some(parse_hex("#5b6078"));
theme.button_border_color = Some(parse_hex("#5b6078"));
theme.input_border_hover_color = Some(parse_hex("#494d64"));
theme.badge_blue_color = Some(parse_hex("#8aadf4"));
theme.badge_gold_color = Some(parse_hex("#eed49f"));
theme.badge_red_color = Some(parse_hex("#ed8796"));
theme.badge_green_color = Some(parse_hex("#a6da95"));
theme.badge_teal_color = Some(parse_hex("#8bd5ca"));
theme.badge_amber_color = Some(parse_hex("#f5a97f"));
theme.badge_gray_color = Some(parse_hex("#a5adcb"));
theme
}
pub fn catppuccin_mocha() -> Self {
let mut theme = Theme::new(
"Catppuccin Mocha",
ThemeVariant::Dark,
parse_hex("#cdd6f4"), parse_hex("#1e1e2e"), parse_hex("#181825"), parse_hex("#313244"), parse_hex("#cba6f7"), );
theme.fg_muted_color = Some(parse_hex("#a6adc8"));
theme.fg_disabled_color = Some(parse_hex("#7f849c"));
theme.surface_secondary_color = Some(parse_hex("#45475a"));
theme.surface_tertiary_color = Some(parse_hex("#585b70"));
theme.border_secondary_color = Some(parse_hex("#585b70"));
theme.border_subtle_color = Some(parse_hex("#181825"));
theme.info_color = Some(parse_hex("#89b4fa"));
theme.success_color = Some(parse_hex("#a6e3a1"));
theme.warning_color = Some(parse_hex("#f9e2af"));
theme.danger_color = Some(parse_hex("#f38ba8"));
theme.button_bg_color = Some(parse_hex("#313244"));
theme.button_bg_hover_color = Some(parse_hex("#45475a"));
theme.button_bg_active_color = Some(parse_hex("#585b70"));
theme.button_border_color = Some(parse_hex("#585b70"));
theme.input_border_hover_color = Some(parse_hex("#45475a"));
theme.badge_blue_color = Some(parse_hex("#89b4fa"));
theme.badge_gold_color = Some(parse_hex("#f9e2af"));
theme.badge_red_color = Some(parse_hex("#f38ba8"));
theme.badge_green_color = Some(parse_hex("#a6e3a1"));
theme.badge_teal_color = Some(parse_hex("#94e2d5"));
theme.badge_amber_color = Some(parse_hex("#fab387"));
theme.badge_gray_color = Some(parse_hex("#a6adc8"));
theme
}
pub fn get_global(cx: &App) -> &Arc<Theme> {
&cx.global::<GlobalTheme>().0
}
}
impl Default for Theme {
fn default() -> Self {
Theme::gruvbox_dark()
}
}
#[derive(Clone, Debug)]
pub struct GlobalTheme(pub Arc<Theme>);
impl Global for GlobalTheme {}
impl Default for GlobalTheme {
fn default() -> Self {
GlobalTheme(Arc::new(Theme::default()))
}
}
pub trait ActiveTheme {
fn theme(&self) -> &Arc<Theme>;
}
impl ActiveTheme for App {
fn theme(&self) -> &Arc<Theme> {
&self.global::<GlobalTheme>().0
}
}
pub fn parse_hex(hex: &str) -> Hsla {
let hex = hex.trim_start_matches('#');
let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(0);
let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0);
let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(0);
let r = r as f32 / 255.0;
let g = g as f32 / 255.0;
let b = b as f32 / 255.0;
let max = r.max(g).max(b);
let min = r.min(g).min(b);
let delta = max - min;
let lightness = (max + min) / 2.0;
let saturation = if delta == 0.0 {
0.0
} else {
delta / (1.0 - (2.0 * lightness - 1.0).abs())
};
let hue = if delta == 0.0 {
0.0
} else if max == r {
60.0 * (((g - b) / delta) % 6.0)
} else if max == g {
60.0 * ((b - r) / delta + 2.0)
} else {
60.0 * ((r - g) / delta + 4.0)
};
let hue = if hue < 0.0 { hue + 360.0 } else { hue };
gpui::hsla(hue / 360.0, saturation, lightness, 1.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_theme() {
let theme = Theme::default();
assert_eq!(theme.name, SharedString::from("Gruvbox Dark"));
assert_eq!(theme.variant, ThemeVariant::Dark);
}
#[test]
fn test_minimal_theme() {
let theme = Theme::new(
"Minimal",
ThemeVariant::Dark,
parse_hex("#ffffff"),
parse_hex("#000000"),
parse_hex("#111111"),
parse_hex("#333333"),
parse_hex("#0066cc"),
);
assert_eq!(theme.button_bg(), theme.surface());
assert_eq!(theme.input_border_focused(), theme.accent());
}
#[test]
fn a_theme_can_rescale_every_control_at_once() {
let mut theme = Theme::default();
assert_eq!(
theme.control(ControlSize::Medium).height.0,
ControlScale::default().medium.height.0
);
theme.controls.medium.height = gpui::Rems(2.0);
assert_eq!(theme.control(ControlSize::Medium).height.0, 2.0);
assert_eq!(
theme.control(ControlSize::Small).height.0,
ControlScale::default().small.height.0
);
}
#[test]
fn test_hex_parsing() {
let color = parse_hex("#ffffff");
assert_eq!(color.l, 1.0);
let color = parse_hex("#000000");
assert_eq!(color.l, 0.0);
}
}