Files
coop/crates/theme/src/colors.rs
T

584 lines
18 KiB
Rust

use gpui::{Hsla, Rgba, hsla};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::scale::{ColorScale, ColorScaleSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize, JsonSchema)]
pub struct ThemeColors {
// Surface colors
pub background: Hsla,
pub surface_background: Hsla,
pub elevated_surface_background: Hsla,
pub panel_background: Hsla,
pub overlay: Hsla,
pub title_bar: Hsla,
pub title_bar_inactive: Hsla,
pub window_border: Hsla,
// Border colors
pub border: Hsla,
pub border_variant: Hsla,
pub border_focused: Hsla,
pub border_selected: Hsla,
pub border_transparent: Hsla,
pub border_disabled: Hsla,
pub ring: Hsla,
// Text colors
pub text: Hsla,
pub text_muted: Hsla,
pub text_placeholder: Hsla,
pub text_accent: Hsla,
pub text_danger: Hsla,
pub text_warning: Hsla,
// Icon colors
pub icon: Hsla,
pub icon_muted: Hsla,
pub icon_accent: Hsla,
// Element colors
pub element_foreground: Hsla,
pub element_background: Hsla,
pub element_hover: Hsla,
pub element_active: Hsla,
pub element_selected: Hsla,
pub element_disabled: Hsla,
// Secondary element colors
pub secondary_foreground: Hsla,
pub secondary_background: Hsla,
pub secondary_hover: Hsla,
pub secondary_active: Hsla,
pub secondary_selected: Hsla,
pub secondary_disabled: Hsla,
// Danger element colors
pub danger_foreground: Hsla,
pub danger_background: Hsla,
pub danger_hover: Hsla,
pub danger_active: Hsla,
pub danger_selected: Hsla,
pub danger_disabled: Hsla,
// Warning element colors
pub warning_foreground: Hsla,
pub warning_background: Hsla,
pub warning_hover: Hsla,
pub warning_active: Hsla,
pub warning_selected: Hsla,
pub warning_disabled: Hsla,
// Ghost element colors
pub ghost_element_background: Hsla,
pub ghost_element_background_alt: Hsla,
pub ghost_element_hover: Hsla,
pub ghost_element_active: Hsla,
pub ghost_element_selected: Hsla,
pub ghost_element_disabled: Hsla,
// Tab colors
pub tab_background: Hsla,
pub tab_foreground: Hsla,
pub tab_hover_background: Hsla,
pub tab_active_background: Hsla,
pub tab_active_foreground: Hsla,
// Scrollbar colors
pub scrollbar_thumb_background: Hsla,
pub scrollbar_thumb_hover_background: Hsla,
pub scrollbar_thumb_border: Hsla,
pub scrollbar_track_background: Hsla,
pub scrollbar_track_border: Hsla,
// Interactive colors
pub drop_target_background: Hsla,
pub cursor: Hsla,
pub selection: Hsla,
}
/// The default colors for the theme.
///
/// Themes that do not specify all colors are refined off of these defaults.
impl ThemeColors {
/// Returns the default colors for light themes.
///
/// Themes that do not specify all colors are refined off of these defaults.
pub(crate) fn light() -> Self {
Self {
background: neutral().light().step_1(),
surface_background: neutral().light().step_2(),
elevated_surface_background: neutral().light().step_3(),
panel_background: neutral().light().step_1(),
overlay: neutral().light_alpha().step_3(),
title_bar: neutral().light().step_2(),
title_bar_inactive: neutral().light().step_1(),
window_border: hsl(240.0, 5.9, 78.0),
border: neutral().light().step_6(),
border_variant: neutral().light().step_4(),
border_focused: brand().light().step_7(),
border_selected: brand().light().step_7(),
border_transparent: gpui::transparent_black(),
border_disabled: neutral().light().step_3(),
ring: brand().light().step_8(),
text: neutral().light().step_12(),
text_muted: neutral().light().step_11(),
text_placeholder: neutral().light().step_10(),
text_accent: brand().light().step_9(),
text_danger: danger().light().step_9(),
text_warning: warning().light().step_9(),
icon: neutral().light().step_11(),
icon_muted: neutral().light().step_10(),
icon_accent: brand().light().step_11(),
element_foreground: brand().light().step_12(),
element_background: brand().light().step_9(),
element_hover: brand().light_alpha().step_10(),
element_active: brand().light().step_10(),
element_selected: brand().light().step_11(),
element_disabled: brand().light_alpha().step_3(),
secondary_foreground: brand().light().step_11(),
secondary_background: brand().light().step_3(),
secondary_hover: brand().light_alpha().step_4(),
secondary_active: brand().light().step_5(),
secondary_selected: brand().light().step_5(),
secondary_disabled: brand().light_alpha().step_3(),
danger_foreground: danger().light().step_12(),
danger_background: danger().light().step_3(),
danger_hover: danger().light_alpha().step_4(),
danger_active: danger().light().step_5(),
danger_selected: danger().light().step_5(),
danger_disabled: danger().light_alpha().step_3(),
warning_foreground: warning().light().step_12(),
warning_background: warning().light().step_3(),
warning_hover: warning().light_alpha().step_4(),
warning_active: warning().light().step_5(),
warning_selected: warning().light().step_5(),
warning_disabled: warning().light_alpha().step_3(),
ghost_element_background: gpui::transparent_black(),
ghost_element_background_alt: neutral().light().step_3(),
ghost_element_hover: neutral().light_alpha().step_4(),
ghost_element_active: neutral().light().step_5(),
ghost_element_selected: neutral().light().step_5(),
ghost_element_disabled: neutral().light_alpha().step_2(),
tab_background: neutral().light().step_3(),
tab_foreground: neutral().light().step_11(),
tab_hover_background: neutral().light_alpha().step_4(),
tab_active_background: neutral().light().step_1(),
tab_active_foreground: neutral().light().step_12(),
scrollbar_thumb_background: neutral().light_alpha().step_3(),
scrollbar_thumb_hover_background: neutral().light_alpha().step_4(),
scrollbar_thumb_border: gpui::transparent_black(),
scrollbar_track_background: gpui::transparent_black(),
scrollbar_track_border: gpui::transparent_black(),
drop_target_background: brand().light_alpha().step_2(),
cursor: hsl(200., 100., 50.),
selection: hsl(200., 100., 50.).alpha(0.25),
}
}
/// Returns the default colors for dark themes.
///
/// Themes that do not specify all colors are refined off of these defaults.
pub(crate) fn dark() -> Self {
Self {
background: neutral().dark().step_1(),
surface_background: neutral().dark().step_2(),
elevated_surface_background: neutral().dark().step_3(),
panel_background: neutral().dark().step_1(),
overlay: neutral().dark_alpha().step_3(),
title_bar: neutral().dark().step_2(),
title_bar_inactive: neutral().dark().step_1(),
window_border: hsl(240.0, 3.7, 28.0),
border: neutral().dark().step_6(),
border_variant: neutral().dark().step_4(),
border_focused: brand().dark().step_7(),
border_selected: brand().dark().step_7(),
border_transparent: gpui::transparent_black(),
border_disabled: neutral().dark().step_3(),
ring: brand().dark().step_8(),
text: neutral().dark().step_12(),
text_muted: neutral().dark().step_11(),
text_placeholder: neutral().dark().step_10(),
text_accent: brand().dark().step_9(),
text_danger: danger().dark().step_9(),
text_warning: warning().dark().step_9(),
icon: neutral().dark().step_11(),
icon_muted: neutral().dark().step_10(),
icon_accent: brand().dark().step_11(),
element_foreground: brand().dark().step_1(),
element_background: brand().dark().step_9(),
element_hover: brand().dark_alpha().step_10(),
element_active: brand().dark().step_10(),
element_selected: brand().dark().step_11(),
element_disabled: brand().dark_alpha().step_3(),
secondary_foreground: brand().dark().step_12(),
secondary_background: brand().dark().step_3(),
secondary_hover: brand().dark_alpha().step_4(),
secondary_active: brand().dark().step_5(),
secondary_selected: brand().dark().step_5(),
secondary_disabled: brand().dark_alpha().step_3(),
danger_foreground: danger().dark().step_12(),
danger_background: danger().dark().step_3(),
danger_hover: danger().dark_alpha().step_4(),
danger_active: danger().dark().step_5(),
danger_selected: danger().dark().step_5(),
danger_disabled: danger().dark_alpha().step_3(),
warning_foreground: warning().dark().step_12(),
warning_background: warning().dark().step_3(),
warning_hover: warning().dark_alpha().step_4(),
warning_active: warning().dark().step_5(),
warning_selected: warning().dark().step_5(),
warning_disabled: warning().dark_alpha().step_3(),
ghost_element_background: gpui::transparent_black(),
ghost_element_background_alt: neutral().dark().step_3(),
ghost_element_hover: neutral().dark_alpha().step_4(),
ghost_element_active: neutral().dark().step_5(),
ghost_element_selected: neutral().dark().step_5(),
ghost_element_disabled: neutral().dark_alpha().step_2(),
tab_background: neutral().dark().step_3(),
tab_foreground: neutral().dark().step_11(),
tab_hover_background: neutral().dark_alpha().step_4(),
tab_active_background: neutral().dark().step_1(),
tab_active_foreground: neutral().dark().step_12(),
scrollbar_thumb_background: neutral().dark_alpha().step_3(),
scrollbar_thumb_hover_background: neutral().dark_alpha().step_4(),
scrollbar_thumb_border: gpui::transparent_black(),
scrollbar_track_background: gpui::transparent_black(),
scrollbar_track_border: gpui::transparent_black(),
drop_target_background: brand().dark_alpha().step_2(),
cursor: hsl(200., 100., 50.),
selection: hsl(200., 100., 50.).alpha(0.25),
}
}
}
fn neutral() -> ColorScaleSet {
gray()
}
fn brand() -> ColorScaleSet {
yellow()
}
fn danger() -> ColorScaleSet {
tomato()
}
fn warning() -> ColorScaleSet {
orange()
}
/// Make a [gpui::Hsla] color.
///
/// - h: 0..360.0
/// - s: 0.0..100.0
/// - l: 0.0..100.0
pub(crate) fn hsl(h: f32, s: f32, l: f32) -> Hsla {
hsla(h / 360., s / 100.0, l / 100.0, 1.0)
}
type StaticColorScale = [&'static str; 12];
struct StaticColorScaleSet {
light: StaticColorScale,
light_alpha: StaticColorScale,
dark: StaticColorScale,
dark_alpha: StaticColorScale,
}
impl TryFrom<StaticColorScaleSet> for ColorScaleSet {
type Error = anyhow::Error;
fn try_from(value: StaticColorScaleSet) -> Result<Self, Self::Error> {
fn to_color_scale(scale: StaticColorScale) -> Result<ColorScale, anyhow::Error> {
scale
.into_iter()
.map(|color| Rgba::try_from(color).map(Hsla::from))
.collect::<Result<Vec<_>, _>>()
.map(ColorScale::from_iter)
}
Ok(Self::new(
to_color_scale(value.light)?,
to_color_scale(value.light_alpha)?,
to_color_scale(value.dark)?,
to_color_scale(value.dark_alpha)?,
))
}
}
pub(crate) fn gray() -> ColorScaleSet {
StaticColorScaleSet {
light: [
"#fcfcfcff",
"#f9f9f9ff",
"#f0f0f0ff",
"#e8e8e8ff",
"#e0e0e0ff",
"#d9d9d9ff",
"#cececeff",
"#bbbbbbff",
"#8d8d8dff",
"#838383ff",
"#646464ff",
"#202020ff",
],
light_alpha: [
"#00000003",
"#00000006",
"#0000000f",
"#00000017",
"#0000001f",
"#00000026",
"#00000031",
"#00000044",
"#00000072",
"#0000007c",
"#0000009b",
"#000000df",
],
dark: [
"#111111ff",
"#191919ff",
"#222222ff",
"#2a2a2aff",
"#313131ff",
"#3a3a3aff",
"#484848ff",
"#606060ff",
"#6e6e6eff",
"#7b7b7bff",
"#b4b4b4ff",
"#eeeeeeff",
],
dark_alpha: [
"#00000000",
"#ffffff09",
"#ffffff12",
"#ffffff1b",
"#ffffff22",
"#ffffff2c",
"#ffffff3b",
"#ffffff55",
"#ffffff64",
"#ffffff72",
"#ffffffaf",
"#ffffffed",
],
}
.try_into()
.unwrap()
}
pub(crate) fn yellow() -> ColorScaleSet {
StaticColorScaleSet {
light: [
"#fdfdf9ff",
"#fefce9ff",
"#fffab8ff",
"#fff394ff",
"#ffe770ff",
"#f3d768ff",
"#e4c767ff",
"#d5ae39ff",
"#ffe629ff",
"#ffdc00ff",
"#9e6c00ff",
"#473b1fff",
],
light_alpha: [
"#aaaa0006",
"#f4dd0016",
"#ffee0047",
"#ffe3016b",
"#ffd5008f",
"#ebbc0097",
"#d2a10098",
"#c99700c6",
"#ffe100d6",
"#ffdc00ff",
"#9e6c00ff",
"#2e2000e0",
],
dark: [
"#14120bff",
"#1b180fff",
"#2d2305ff",
"#362b00ff",
"#433500ff",
"#524202ff",
"#665417ff",
"#836a21ff",
"#ffe629ff",
"#ffff57ff",
"#f5e147ff",
"#f6eeb4ff",
],
dark_alpha: [
"#d1510004",
"#f9b4000b",
"#ffaa001e",
"#fdb70028",
"#febb0036",
"#fec40046",
"#fdcb225c",
"#fdca327b",
"#ffe629ff",
"#ffff57ff",
"#fee949f5",
"#fef6baf6",
],
}
.try_into()
.unwrap()
}
pub(crate) fn orange() -> ColorScaleSet {
StaticColorScaleSet {
light: [
"#fefcfbff",
"#fff7edff",
"#ffefd6ff",
"#ffdfb5ff",
"#ffd19aff",
"#ffc182ff",
"#f5ae73ff",
"#ec9455ff",
"#f76b15ff",
"#ef5f00ff",
"#cc4e00ff",
"#582d1dff",
],
light_alpha: [
"#c0400004",
"#ff8e0012",
"#ff9c0029",
"#ff91014a",
"#ff8b0065",
"#ff81007d",
"#ed6c008c",
"#e35f00aa",
"#f65e00ea",
"#ef5f00ff",
"#cc4e00ff",
"#431200e2",
],
dark: [
"#17120eff",
"#1e160fff",
"#331e0bff",
"#462100ff",
"#562800ff",
"#66350cff",
"#7e451dff",
"#a35829ff",
"#f76b15ff",
"#ff801fff",
"#ffa057ff",
"#ffe0c2ff",
],
dark_alpha: [
"#ec360007",
"#fe6d000e",
"#fb6a0025",
"#ff590039",
"#ff61004a",
"#fd75045c",
"#ff832c75",
"#fe84389d",
"#fe6d15f7",
"#ff801fff",
"#ffa057ff",
"#ffe0c2ff",
],
}
.try_into()
.unwrap()
}
pub(crate) fn tomato() -> ColorScaleSet {
StaticColorScaleSet {
light: [
"#fffcfcff",
"#fff8f7ff",
"#feebe7ff",
"#ffdcd3ff",
"#ffcdc2ff",
"#fdbdafff",
"#f5a898ff",
"#ec8e7bff",
"#e54d2eff",
"#dd4425ff",
"#d13415ff",
"#5c271fff",
],
light_alpha: [
"#ff000003",
"#ff200008",
"#f52b0018",
"#ff35002c",
"#ff2e003d",
"#f92d0050",
"#e7280067",
"#db250084",
"#df2600d1",
"#d72400da",
"#cd2200ea",
"#460900e0",
],
dark: [
"#181111ff",
"#1f1513ff",
"#391714ff",
"#4e1511ff",
"#5e1c16ff",
"#6e2920ff",
"#853a2dff",
"#ac4d39ff",
"#e54d2eff",
"#ec6142ff",
"#ff977dff",
"#fbd3cbff",
],
dark_alpha: [
"#f1121208",
"#ff55330f",
"#ff35232b",
"#fd201142",
"#fe332153",
"#ff4f3864",
"#fd644a7d",
"#fe6d4ea7",
"#fe5431e4",
"#ff6847eb",
"#ff977dff",
"#ffd6cefb",
],
}
.try_into()
.unwrap()
}