pub mod color;
pub mod palette;
use std::sync::RwLock;
use gpui_kit::component::{Theme, ThemeMode};
use gpui_kit::{App, Pixels, Window, px, rgba};
pub use color::{Colors, colors, contrast, rgb8, rgb_hsla};
pub use palette::{Accent, Palette, Rgb};
pub const XS: f32 = 4.;
pub const SM: f32 = 8.;
pub const MD: f32 = 12.;
pub const LG: f32 = 16.;
pub const XL: f32 = 24.;
pub const XXL: f32 = 32.;
pub const FONT_SIZE: f32 = 15.;
pub const FONT_RANGE: (f32, f32) = (12., 18.);
pub const RADIUS_SM: f32 = 4.;
pub const RADIUS: f32 = 6.;
pub const RADIUS_LG: f32 = 8.;
pub const PANE_GAP: f32 = 4.;
pub const PANE_PADDING: f32 = 8.;
pub const LABEL_W: f32 = 112.;
pub const CONTROL_MIN_W: f32 = 140.;
pub const TARGET_MIN: f32 = 24.;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Look {
pub dark: bool,
pub palette: Palette,
pub accent: Option<Rgb>,
pub font_size: f32,
}
impl Look {
pub const fn new(palette: Palette) -> Self {
Look { dark: true, palette, accent: None, font_size: FONT_SIZE }
}
pub fn active_palette(&self) -> Palette {
match self.accent {
Some(rgb) => Palette::custom(rgb),
None => self.palette,
}
}
pub const fn with_dark(self, dark: bool) -> Self {
Look { dark, ..self }
}
pub const fn with_palette(self, palette: Palette) -> Self {
Look { palette, ..self }
}
pub const fn with_accent(self, accent: Option<Rgb>) -> Self {
Look { accent, ..self }
}
pub fn with_font_size(self, font_size: f32) -> Self {
Look { font_size: font_size.round().clamp(FONT_RANGE.0, FONT_RANGE.1), ..self }
}
}
impl Default for Look {
fn default() -> Self {
Look::new(Palette::LIME)
}
}
static LOOK: RwLock<Look> = RwLock::new(Look::new(Palette::LIME));
pub fn set_look(look: Look) {
let look = look.with_font_size(look.font_size);
*LOOK.write().unwrap_or_else(|e| e.into_inner()) = look;
}
pub fn look() -> Look {
*LOOK.read().unwrap_or_else(|e| e.into_inner())
}
pub fn is_dark() -> bool {
look().dark
}
pub fn system_dark(window: &Window) -> bool {
use gpui_kit::WindowAppearance as W;
matches!(window.appearance(), W::Dark | W::VibrantDark)
}
pub fn use_look(look: Look, cx: &mut App) {
set_look(look);
apply(cx);
}
pub fn apply(cx: &mut App) {
let l = look();
Theme::change(if l.dark { ThemeMode::Dark } else { ThemeMode::Light }, None, cx);
let c = Colors::resolve(&l);
let (on_danger, on_success, on_warning) = (palette::best_text_on(c.danger), palette::best_text_on(c.success), palette::best_text_on(c.warning));
Theme::update(cx, |t| {
t.font_size = px(l.font_size);
t.radius = px(RADIUS);
t.radius_lg = px(RADIUS_LG);
t.shadow = true;
let k = &mut t.colors;
k.background = c.panel;
k.foreground = c.text;
k.muted = c.raised;
k.muted_foreground = c.text_muted;
k.border = c.border;
k.input = c.hover;
k.ring = c.accent_mark;
k.caret = c.text;
k.selection = c.accent.opacity(0.45);
k.popover = c.raised;
k.popover_foreground = c.text;
k.sidebar = c.chrome;
k.sidebar_foreground = c.text;
k.sidebar_border = c.border;
k.sidebar_accent = c.control;
k.sidebar_accent_foreground = c.text;
k.sidebar_primary = c.accent;
k.sidebar_primary_foreground = c.on_accent;
k.primary = c.accent;
k.primary_hover = c.accent_hover;
k.primary_active = c.accent;
k.primary_foreground = c.on_accent;
k.secondary = c.control;
k.secondary_hover = c.hover;
k.secondary_active = c.hover;
k.secondary_foreground = c.text;
k.accent = c.control;
k.accent_foreground = c.text;
k.title_bar = c.chrome;
k.title_bar_border = c.border;
k.tab_bar = c.chrome;
k.tab = c.chrome;
k.tab_active = c.panel;
k.tab_foreground = c.text_muted;
k.tab_active_foreground = c.text;
k.list = c.panel;
k.list_even = c.panel;
k.list_hover = c.control;
k.list_active = c.accent.opacity(0.25);
k.list_active_border = c.accent_mark;
k.list_head = c.raised;
k.table = c.panel;
k.table_even = c.raised;
k.table_head = c.raised;
k.table_head_foreground = c.text_muted;
k.table_active = c.accent.opacity(0.25);
k.table_active_border = c.accent_mark;
k.danger = c.danger;
k.danger_foreground = on_danger;
k.success = c.success;
k.success_foreground = on_success;
k.warning = c.warning;
k.warning_foreground = on_warning;
k.info = c.accent_mark;
k.link = c.accent_mark;
k.scrollbar = rgba(0x00000000).into();
k.scrollbar_thumb = if l.dark { rgba(0xffffff33).into() } else { rgba(0x00000033).into() };
k.scrollbar_thumb_hover = if l.dark { rgba(0xffffff55).into() } else { rgba(0x00000055).into() };
k.window_border = c.border;
k.overlay = rgba(0x00000080).into();
k.drag_border = c.accent_mark;
k.drop_target = c.accent.opacity(0.2);
k.chart_grid = c.border;
});
}
pub fn sp(v: f32) -> Pixels {
px(v)
}