diff --git a/Cargo.lock b/Cargo.lock index 1b0c6e4bb9..728fc695ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7925,6 +7925,7 @@ name = "theme" version = "0.1.0" dependencies = [ "anyhow", + "color", "fs", "gpui", "indexmap 1.9.3", diff --git a/crates/color/src/color.rs b/crates/color/src/color.rs index 77818eb7b8..8a7f3f1752 100644 --- a/crates/color/src/color.rs +++ b/crates/color/src/color.rs @@ -88,25 +88,28 @@ pub struct Color { } impl Color { - /// Creates a new [`Color`] - pub fn new(hue: f32, saturation: f32, lightness: f32) -> Self { - let hsl = hsl(hue, saturation, lightness); - - Self { value: hsl.into() } - } - /// Creates a new [`Color`] with an alpha value. - pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Self { + pub fn new(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Self { Self { value: Hsla::new(hue, saturation, lightness, alpha), } } + /// Creates a new [`Color`] with an alpha value of `1.0`. + pub fn hsl(hue: f32, saturation: f32, lightness: f32) -> Self { + Self::new(hue, saturation, lightness, 1.0) + } + /// Returns the [`palette::Hsla`] value of this color. pub fn value(&self) -> Hsla { self.value } + /// Returns a set of states for this color. + pub fn states(&self, is_light: bool) -> ColorStates { + states_for_color(*self, is_light) + } + /// Mixes this color with another [`palette::Hsl`] color at the given `mix_ratio`. pub fn mix(&self, other: Hsl, mix_ratio: f32) -> Self { let mixed = self.value.mix(other.into(), mix_ratio); @@ -116,3 +119,41 @@ impl Color { } } } + +/// A set of colors for different states of an element. +#[derive(Debug, Copy, Clone)] +pub struct ColorStates { + /// The default color. + pub default: Color, + /// The color when the mouse is hovering over the element. + pub hover: Color, + /// The color when the mouse button is held down on the element. + pub active: Color, + /// The color when the element is focused with the keyboard. + pub focused: Color, + /// The color when the element is disabled. + pub disabled: Color, +} + +/// Returns a set of colors for different states of an element. +/// +/// todo!("Test and improve this function") +pub fn states_for_color(color: Color, is_light: bool) -> ColorStates { + let hover_lightness = if is_light { 0.9 } else { 0.1 }; + let active_lightness = if is_light { 0.8 } else { 0.2 }; + let focused_lightness = if is_light { 0.7 } else { 0.3 }; + let disabled_lightness = if is_light { 0.6 } else { 0.5 }; + + let hover = color.mix(hsl(0.0, 0.0, hover_lightness), 0.1); + let active = color.mix(hsl(0.0, 0.0, active_lightness), 0.1); + let focused = color.mix(hsl(0.0, 0.0, focused_lightness), 0.1); + let disabled = color.mix(hsl(0.0, 0.0, disabled_lightness), 0.1); + + ColorStates { + default: color, + hover, + active, + focused, + disabled, + } +} diff --git a/crates/theme/Cargo.toml b/crates/theme/Cargo.toml index 1c30176b25..428bcaac10 100644 --- a/crates/theme/Cargo.toml +++ b/crates/theme/Cargo.toml @@ -34,6 +34,7 @@ story = { path = "../story", optional = true } toml.workspace = true uuid.workspace = true util = { path = "../util" } +color = {path = "../color"} itertools = { version = "0.11.0", optional = true } [dev-dependencies] diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index f8d90b7bdc..c40d7c8ceb 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -147,3 +147,10 @@ pub fn color_alpha(color: Hsla, alpha: f32) -> Hsla { color.a = alpha; color } + +pub fn to_gpui_hsla(color: color::Color) -> gpui::Hsla { + let hsla = color.value(); + let hue: f32 = hsla.hue.into(); + + gpui::hsla(hue / 360.0, hsla.saturation, hsla.lightness, hsla.alpha) +}