use crate::utils::{is_dark, lighten, darken, mix};
#[derive(Clone, Copy, Debug)]
pub struct Palette {
pub bg: u32,
pub text: u32,
pub primary: u32,
pub accent: u32,
pub success: u32,
pub error: u32,
pub warning: u32,
}
impl Default for Palette {
fn default() -> Self {
Self::dark()
}
}
impl Palette {
pub fn dark() -> Self {
Self {
bg: 0x1e1e1e,
text: 0xffffff,
primary: 0x3b82f6,
accent: 0x0078d4,
success: 0x4CAF50,
error: 0xF44336,
warning: 0xF57C00,
}
}
pub fn light() -> Self {
Self {
bg: 0xf5f5f5,
text: 0x1a1a1a,
primary: 0x3b82f6,
accent: 0x0078d4,
success: 0x4CAF50,
error: 0xF44336,
warning: 0xF57C00,
}
}
pub fn with_bg(mut self, color: u32) -> Self {
self.bg = color;
self
}
pub fn with_text(mut self, color: u32) -> Self {
self.text = color;
self
}
pub fn with_primary(mut self, color: u32) -> Self {
self.primary = color;
self
}
pub fn with_accent(mut self, color: u32) -> Self {
self.accent = color;
self
}
pub fn with_success(mut self, color: u32) -> Self {
self.success = color;
self
}
pub fn with_error(mut self, color: u32) -> Self {
self.error = color;
self
}
pub fn with_warning(mut self, color: u32) -> Self {
self.warning = color;
self
}
}
#[derive(Clone, Copy, Debug)]
pub struct Theme {
pub bg_primary: u32,
pub bg_secondary: u32,
pub bg_input: u32,
pub bg_input_hover: u32,
pub bg_hover: u32,
pub bg_section_header: u32,
pub bg_section_header_hover: u32,
pub bg_white: u32,
pub bg_light_hover: u32,
pub text_primary: u32,
pub text_label: u32,
pub text_section_header: u32,
pub text_value: u32,
pub text_muted: u32,
pub text_placeholder: u32,
pub text_dimmed: u32,
pub text_icon: u32,
pub text_dark: u32,
pub text_black: u32,
pub border_default: u32,
pub border_checkbox: u32,
pub border_input: u32,
pub border_menu: u32,
pub border_focus: u32,
pub border_focus_on_color: u32,
pub border_error: u32,
pub primary: u32,
pub primary_hover: u32,
pub primary_active: u32,
pub accent: u32,
pub success: u32,
pub error: u32,
pub warning: u32,
pub error_text: u32,
pub tooltip_bg: u32,
pub tooltip_border: u32,
pub tooltip_text: u32,
pub selection: u32,
pub disabled_bg: u32,
pub disabled_text: u32,
pub secondary_bg: u32,
pub secondary_bg_hover: u32,
pub secondary_bg_active: u32,
pub secondary_border: u32,
pub bg_tab_hover: u32,
pub border_tab_active: u32,
pub delete_bg: u32,
pub delete_bg_hover: u32,
pub bg_path_hover: u32,
}
impl Default for Theme {
fn default() -> Self {
Self::dark()
}
}
impl gpui::Global for Theme {}
impl Theme {
pub fn dark() -> Self {
Self {
bg_primary: 0x1e1e1e,
bg_secondary: 0x252525,
bg_input: 0x2a2a2a,
bg_input_hover: 0x3a3a3a,
bg_hover: 0x4a4a4a,
bg_section_header: 0x363636,
bg_section_header_hover: 0x404040,
bg_white: 0xffffff,
bg_light_hover: 0xf0f0f0,
text_primary: 0xffffff,
text_label: 0xeeeeee,
text_section_header: 0xdddddd,
text_value: 0xcccccc,
text_muted: 0xaaaaaa,
text_placeholder: 0x999999,
text_dimmed: 0x888888,
text_icon: 0x666666,
text_dark: 0x333333,
text_black: 0x000000,
border_default: 0x444444,
border_checkbox: 0x666666,
border_input: 0x999999,
border_menu: 0xcccccc,
border_focus: 0x0078d4,
border_focus_on_color: 0xffffff, border_error: 0x662222,
primary: 0x3b82f6,
primary_hover: 0x2563eb,
primary_active: 0x1d4ed8,
accent: 0x0078d4,
success: 0x4CAF50,
error: 0xF44336,
warning: 0xF57C00,
error_text: 0xFF6B6B,
tooltip_bg: 0x2a2a2a,
tooltip_border: 0x444444,
tooltip_text: 0xeeeeee,
selection: 0x264F78,
disabled_bg: 0x6b7280,
disabled_text: 0x9ca3af,
secondary_bg: 0x374151,
secondary_bg_hover: 0x4b5563,
secondary_bg_active: 0x1f2937,
secondary_border: 0x6b7280,
bg_tab_hover: 0x323232,
border_tab_active: 0x007acc,
delete_bg: 0x4a3a3a,
delete_bg_hover: 0x5a4a4a,
bg_path_hover: 0x333333,
}
}
pub fn light() -> Self {
Self {
bg_primary: 0xf5f5f5,
bg_secondary: 0xffffff,
bg_input: 0xffffff,
bg_input_hover: 0xf0f0f0,
bg_hover: 0xe0e0e0,
bg_section_header: 0xeeeeee,
bg_section_header_hover: 0xe5e5e5,
bg_white: 0xffffff,
bg_light_hover: 0xf5f5f5,
text_primary: 0x1a1a1a,
text_label: 0x333333,
text_section_header: 0x444444,
text_value: 0x555555,
text_muted: 0x777777,
text_placeholder: 0x999999,
text_dimmed: 0xaaaaaa,
text_icon: 0x888888,
text_dark: 0x333333,
text_black: 0x000000,
border_default: 0xcccccc,
border_checkbox: 0xaaaaaa,
border_input: 0x444444,
border_menu: 0xdddddd,
border_focus: 0x0078d4,
border_focus_on_color: 0xffffff, border_error: 0xffcccc,
primary: 0x3b82f6,
primary_hover: 0x2563eb,
primary_active: 0x1d4ed8,
accent: 0x0078d4,
success: 0x4CAF50,
error: 0xF44336,
warning: 0xF57C00,
error_text: 0xdc3545,
tooltip_bg: 0xffffff,
tooltip_border: 0xaaaaaa,
tooltip_text: 0x333333,
selection: 0xADD6FF,
disabled_bg: 0xd1d5db,
disabled_text: 0x9ca3af,
secondary_bg: 0xe5e7eb,
secondary_bg_hover: 0xd1d5db,
secondary_bg_active: 0xf3f4f6,
secondary_border: 0x9ca3af,
bg_tab_hover: 0xe5e5e5,
border_tab_active: 0x0078d4,
delete_bg: 0xfee2e2,
delete_bg_hover: 0xfecaca,
bg_path_hover: 0xf5f5f5,
}
}
pub fn from_palette(palette: Palette) -> Self {
let dark_mode = is_dark(palette.bg);
let opposite = if dark_mode { 0xFFFFFF } else { 0x000000 };
let bg_primary = palette.bg;
let bg_secondary = if dark_mode {
lighten(palette.bg, 0.03)
} else {
0xffffff };
let bg_input = if dark_mode {
lighten(palette.bg, 0.05)
} else {
0xffffff
};
let bg_input_hover = if dark_mode {
lighten(palette.bg, 0.12)
} else {
darken(palette.bg, 0.03)
};
let bg_hover = if dark_mode {
lighten(palette.bg, 0.18)
} else {
darken(palette.bg, 0.12)
};
let bg_section_header = if dark_mode {
lighten(palette.bg, 0.10)
} else {
darken(palette.bg, 0.04)
};
let bg_section_header_hover = if dark_mode {
lighten(palette.bg, 0.14)
} else {
darken(palette.bg, 0.08)
};
let text_primary = palette.text;
let text_label = mix(palette.text, opposite, 0.07);
let text_section_header = mix(palette.text, opposite, 0.13);
let text_value = mix(palette.text, opposite, 0.20);
let text_muted = mix(palette.text, opposite, 0.33);
let text_placeholder = mix(palette.text, opposite, 0.40);
let text_dimmed = mix(palette.text, opposite, 0.47);
let text_icon = mix(palette.text, opposite, 0.60);
let border_default = mix(palette.bg, palette.text, 0.16);
let border_checkbox = mix(palette.bg, palette.text, 0.30);
let border_input = mix(palette.bg, palette.text, 0.50);
let border_menu = mix(palette.bg, palette.text, 0.70);
let border_focus = palette.accent;
let border_focus_on_color = 0xffffff; let border_error = if dark_mode {
darken(palette.error, 0.60)
} else {
lighten(palette.error, 0.60)
};
let primary_hover = darken(palette.primary, 0.15);
let primary_active = darken(palette.primary, 0.25);
let error_text = if dark_mode {
lighten(palette.error, 0.20)
} else {
darken(palette.error, 0.10)
};
let tooltip_bg = bg_input;
let tooltip_border = border_default;
let tooltip_text = text_label;
let selection = if dark_mode {
mix(palette.accent, palette.bg, 0.50)
} else {
lighten(palette.accent, 0.60)
};
let disabled_bg = mix(palette.bg, palette.text, 0.35);
let disabled_text = mix(palette.bg, palette.text, 0.50);
let secondary_bg = if dark_mode {
lighten(palette.bg, 0.12)
} else {
darken(palette.bg, 0.10)
};
let secondary_bg_hover = if dark_mode {
lighten(palette.bg, 0.20)
} else {
darken(palette.bg, 0.15)
};
let secondary_bg_active = if dark_mode {
darken(palette.bg, 0.05)
} else {
lighten(palette.bg, 0.02)
};
let secondary_border = disabled_bg;
let bg_tab_hover = if dark_mode {
lighten(palette.bg, 0.08)
} else {
darken(palette.bg, 0.06)
};
let border_tab_active = palette.accent;
let delete_bg = if dark_mode {
mix(palette.bg, palette.error, 0.15)
} else {
lighten(palette.error, 0.80)
};
let delete_bg_hover = if dark_mode {
mix(palette.bg, palette.error, 0.25)
} else {
lighten(palette.error, 0.70)
};
let bg_path_hover = if dark_mode {
lighten(palette.bg, 0.08)
} else {
darken(palette.bg, 0.02)
};
Self {
bg_primary,
bg_secondary,
bg_input,
bg_input_hover,
bg_hover,
bg_section_header,
bg_section_header_hover,
bg_white: 0xffffff,
bg_light_hover: 0xf0f0f0,
text_primary,
text_label,
text_section_header,
text_value,
text_muted,
text_placeholder,
text_dimmed,
text_icon,
text_dark: 0x333333,
text_black: 0x000000,
border_default,
border_checkbox,
border_input,
border_menu,
border_focus,
border_focus_on_color,
border_error,
primary: palette.primary,
primary_hover,
primary_active,
accent: palette.accent,
success: palette.success,
error: palette.error,
warning: palette.warning,
error_text,
tooltip_bg,
tooltip_border,
tooltip_text,
selection,
disabled_bg,
disabled_text,
secondary_bg,
secondary_bg_hover,
secondary_bg_active,
secondary_border,
bg_tab_hover,
border_tab_active,
delete_bg,
delete_bg_hover,
bg_path_hover,
}
}
pub fn with_accent(mut self, color: u32) -> Self {
self.accent = color;
self
}
pub fn with_primary(mut self, color: u32) -> Self {
self.primary = color;
self
}
pub fn with_primary_hover(mut self, color: u32) -> Self {
self.primary_hover = color;
self
}
pub fn with_border_focus(mut self, color: u32) -> Self {
self.border_focus = color;
self
}
pub fn with_border_focus_on_color(mut self, color: u32) -> Self {
self.border_focus_on_color = color;
self
}
pub fn with_success(mut self, color: u32) -> Self {
self.success = color;
self
}
pub fn with_error(mut self, color: u32) -> Self {
self.error = color;
self
}
pub fn with_warning(mut self, color: u32) -> Self {
self.warning = color;
self
}
pub fn with_bg_primary(mut self, color: u32) -> Self {
self.bg_primary = color;
self
}
pub fn with_bg_input(mut self, color: u32) -> Self {
self.bg_input = color;
self
}
pub fn with_text_primary(mut self, color: u32) -> Self {
self.text_primary = color;
self
}
pub fn with_bg_secondary(mut self, color: u32) -> Self {
self.bg_secondary = color;
self
}
pub fn with_bg_input_hover(mut self, color: u32) -> Self {
self.bg_input_hover = color;
self
}
pub fn with_bg_hover(mut self, color: u32) -> Self {
self.bg_hover = color;
self
}
pub fn with_bg_section_header(mut self, color: u32) -> Self {
self.bg_section_header = color;
self
}
pub fn with_bg_section_header_hover(mut self, color: u32) -> Self {
self.bg_section_header_hover = color;
self
}
pub fn with_bg_white(mut self, color: u32) -> Self {
self.bg_white = color;
self
}
pub fn with_bg_light_hover(mut self, color: u32) -> Self {
self.bg_light_hover = color;
self
}
pub fn with_text_label(mut self, color: u32) -> Self {
self.text_label = color;
self
}
pub fn with_text_section_header(mut self, color: u32) -> Self {
self.text_section_header = color;
self
}
pub fn with_text_value(mut self, color: u32) -> Self {
self.text_value = color;
self
}
pub fn with_text_muted(mut self, color: u32) -> Self {
self.text_muted = color;
self
}
pub fn with_text_placeholder(mut self, color: u32) -> Self {
self.text_placeholder = color;
self
}
pub fn with_text_dimmed(mut self, color: u32) -> Self {
self.text_dimmed = color;
self
}
pub fn with_text_icon(mut self, color: u32) -> Self {
self.text_icon = color;
self
}
pub fn with_text_dark(mut self, color: u32) -> Self {
self.text_dark = color;
self
}
pub fn with_text_black(mut self, color: u32) -> Self {
self.text_black = color;
self
}
pub fn with_border_default(mut self, color: u32) -> Self {
self.border_default = color;
self
}
pub fn with_border_checkbox(mut self, color: u32) -> Self {
self.border_checkbox = color;
self
}
pub fn with_border_input(mut self, color: u32) -> Self {
self.border_input = color;
self
}
pub fn with_border_menu(mut self, color: u32) -> Self {
self.border_menu = color;
self
}
pub fn with_border_error(mut self, color: u32) -> Self {
self.border_error = color;
self
}
pub fn with_primary_active(mut self, color: u32) -> Self {
self.primary_active = color;
self
}
pub fn with_error_text(mut self, color: u32) -> Self {
self.error_text = color;
self
}
pub fn with_tooltip_bg(mut self, color: u32) -> Self {
self.tooltip_bg = color;
self
}
pub fn with_tooltip_border(mut self, color: u32) -> Self {
self.tooltip_border = color;
self
}
pub fn with_tooltip_text(mut self, color: u32) -> Self {
self.tooltip_text = color;
self
}
pub fn with_selection(mut self, color: u32) -> Self {
self.selection = color;
self
}
pub fn with_disabled_bg(mut self, color: u32) -> Self {
self.disabled_bg = color;
self
}
pub fn with_disabled_text(mut self, color: u32) -> Self {
self.disabled_text = color;
self
}
pub fn with_secondary_bg(mut self, color: u32) -> Self {
self.secondary_bg = color;
self
}
pub fn with_secondary_bg_hover(mut self, color: u32) -> Self {
self.secondary_bg_hover = color;
self
}
pub fn with_secondary_bg_active(mut self, color: u32) -> Self {
self.secondary_bg_active = color;
self
}
pub fn with_secondary_border(mut self, color: u32) -> Self {
self.secondary_border = color;
self
}
pub fn with_bg_tab_hover(mut self, color: u32) -> Self {
self.bg_tab_hover = color;
self
}
pub fn with_border_tab_active(mut self, color: u32) -> Self {
self.border_tab_active = color;
self
}
pub fn with_delete_bg(mut self, color: u32) -> Self {
self.delete_bg = color;
self
}
pub fn with_delete_bg_hover(mut self, color: u32) -> Self {
self.delete_bg_hover = color;
self
}
pub fn with_bg_path_hover(mut self, color: u32) -> Self {
self.bg_path_hover = color;
self
}
}
pub fn get_theme(cx: &gpui::App) -> Theme {
cx.try_global::<Theme>()
.copied()
.unwrap_or_else(Theme::dark)
}
pub fn get_theme_or(cx: &gpui::App, custom: Option<&Theme>) -> Theme {
custom.copied().unwrap_or_else(|| get_theme(cx))
}