wip: refactor
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,444 @@
|
||||
use crate::scroll::ScrollbarShow;
|
||||
use colors::hsl;
|
||||
use gpui::{
|
||||
blue, hsla, transparent_black, AppContext, Global, Hsla, ModelContext, SharedString,
|
||||
ViewContext, WindowAppearance, WindowContext,
|
||||
};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub mod colors;
|
||||
pub mod scale;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ThemeColors {
|
||||
pub border: Hsla,
|
||||
pub window_border: Hsla,
|
||||
pub accent: Hsla,
|
||||
pub accent_foreground: Hsla,
|
||||
pub background: Hsla,
|
||||
pub card: Hsla,
|
||||
pub card_foreground: Hsla,
|
||||
pub danger: Hsla,
|
||||
pub danger_active: Hsla,
|
||||
pub danger_foreground: Hsla,
|
||||
pub danger_hover: Hsla,
|
||||
pub drag_border: Hsla,
|
||||
pub drop_target: Hsla,
|
||||
pub foreground: Hsla,
|
||||
pub input: Hsla,
|
||||
pub link: Hsla,
|
||||
pub link_active: Hsla,
|
||||
pub link_hover: Hsla,
|
||||
pub list: Hsla,
|
||||
pub list_active: Hsla,
|
||||
pub list_active_border: Hsla,
|
||||
pub list_even: Hsla,
|
||||
pub list_head: Hsla,
|
||||
pub list_hover: Hsla,
|
||||
pub muted: Hsla,
|
||||
pub muted_foreground: Hsla,
|
||||
pub popover: Hsla,
|
||||
pub popover_foreground: Hsla,
|
||||
pub primary: Hsla,
|
||||
pub primary_active: Hsla,
|
||||
pub primary_foreground: Hsla,
|
||||
pub primary_hover: Hsla,
|
||||
pub progress_bar: Hsla,
|
||||
pub ring: Hsla,
|
||||
pub scrollbar: Hsla,
|
||||
pub scrollbar_thumb: Hsla,
|
||||
pub scrollbar_thumb_hover: Hsla,
|
||||
pub secondary: Hsla,
|
||||
pub secondary_active: Hsla,
|
||||
pub secondary_foreground: Hsla,
|
||||
pub secondary_hover: Hsla,
|
||||
pub selection: Hsla,
|
||||
pub skeleton: Hsla,
|
||||
pub slider_bar: Hsla,
|
||||
pub slider_thumb: Hsla,
|
||||
pub tab: Hsla,
|
||||
pub tab_active: Hsla,
|
||||
pub tab_active_foreground: Hsla,
|
||||
pub tab_bar: Hsla,
|
||||
pub tab_foreground: Hsla,
|
||||
pub title_bar: Hsla,
|
||||
pub title_bar_border: Hsla,
|
||||
}
|
||||
|
||||
impl ThemeColors {
|
||||
pub fn light() -> Self {
|
||||
Self {
|
||||
accent: hsl(240.0, 5.0, 96.0),
|
||||
accent_foreground: hsl(240.0, 5.9, 10.0),
|
||||
background: hsl(0.0, 0.0, 100.),
|
||||
border: hsl(240.0, 5.9, 90.0),
|
||||
window_border: hsl(240.0, 5.9, 78.0),
|
||||
card: hsl(0.0, 0.0, 100.0),
|
||||
card_foreground: hsl(240.0, 10.0, 3.9),
|
||||
danger: hsl(0.0, 84.2, 60.2),
|
||||
danger_active: hsl(0.0, 84.2, 47.0),
|
||||
danger_foreground: hsl(0.0, 0.0, 98.0),
|
||||
danger_hover: hsl(0.0, 84.2, 65.0),
|
||||
drag_border: blue(),
|
||||
drop_target: hsl(235.0, 30., 44.0).opacity(0.25),
|
||||
foreground: hsl(240.0, 10., 3.9),
|
||||
input: hsl(240.0, 5.9, 90.0),
|
||||
link: hsl(221.0, 83.0, 53.0),
|
||||
link_active: hsl(221.0, 83.0, 53.0).darken(0.2),
|
||||
link_hover: hsl(221.0, 83.0, 53.0).lighten(0.2),
|
||||
list: hsl(0.0, 0.0, 100.),
|
||||
list_active: hsl(211.0, 97.0, 85.0).opacity(0.2),
|
||||
list_active_border: hsl(211.0, 97.0, 85.0),
|
||||
list_even: hsl(240.0, 5.0, 96.0),
|
||||
list_head: hsl(0.0, 0.0, 100.),
|
||||
list_hover: hsl(240.0, 4.8, 95.0),
|
||||
muted: hsl(240.0, 4.8, 95.9),
|
||||
muted_foreground: hsl(240.0, 3.8, 46.1),
|
||||
popover: hsl(0.0, 0.0, 100.0),
|
||||
popover_foreground: hsl(240.0, 10.0, 3.9),
|
||||
primary: hsl(223.0, 5.9, 10.0),
|
||||
primary_active: hsl(223.0, 1.9, 25.0),
|
||||
primary_foreground: hsl(223.0, 0.0, 98.0),
|
||||
primary_hover: hsl(223.0, 5.9, 15.0),
|
||||
progress_bar: hsl(223.0, 5.9, 10.0),
|
||||
ring: hsl(240.0, 5.9, 65.0),
|
||||
scrollbar: hsl(0., 0., 97.).opacity(0.75),
|
||||
scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9),
|
||||
scrollbar_thumb_hover: hsl(0., 0., 59.),
|
||||
secondary: hsl(240.0, 5.9, 96.9),
|
||||
secondary_active: hsl(240.0, 5.9, 90.),
|
||||
secondary_foreground: hsl(240.0, 59.0, 10.),
|
||||
secondary_hover: hsl(240.0, 5.9, 98.),
|
||||
selection: hsl(211.0, 97.0, 85.0),
|
||||
skeleton: hsl(223.0, 5.9, 10.0).opacity(0.1),
|
||||
slider_bar: hsl(223.0, 5.9, 10.0),
|
||||
slider_thumb: hsl(0.0, 0.0, 100.0),
|
||||
tab: transparent_black(),
|
||||
tab_active: hsl(0.0, 0.0, 100.0),
|
||||
tab_active_foreground: hsl(240.0, 10., 3.9),
|
||||
tab_bar: hsl(240.0, 4.8, 95.9),
|
||||
tab_foreground: hsl(240.0, 10., 3.9),
|
||||
title_bar: hsl(0.0, 0.0, 98.0),
|
||||
title_bar_border: hsl(220.0, 13.0, 91.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dark() -> Self {
|
||||
Self {
|
||||
accent: hsl(240.0, 3.7, 15.9),
|
||||
accent_foreground: hsl(0.0, 0.0, 78.0),
|
||||
background: hsl(0.0, 0.0, 8.0),
|
||||
border: hsl(240.0, 3.7, 16.9),
|
||||
window_border: hsl(240.0, 3.7, 28.0),
|
||||
card: hsl(0.0, 0.0, 8.0),
|
||||
card_foreground: hsl(0.0, 0.0, 78.0),
|
||||
danger: hsl(0.0, 62.8, 30.6),
|
||||
danger_active: hsl(0.0, 62.8, 20.6),
|
||||
danger_foreground: hsl(0.0, 0.0, 78.0),
|
||||
danger_hover: hsl(0.0, 62.8, 35.6),
|
||||
drag_border: blue(),
|
||||
drop_target: hsl(235.0, 30., 44.0).opacity(0.1),
|
||||
foreground: hsl(0., 0., 78.),
|
||||
input: hsl(240.0, 3.7, 15.9),
|
||||
link: hsl(221.0, 83.0, 53.0),
|
||||
link_active: hsl(221.0, 83.0, 53.0).darken(0.2),
|
||||
link_hover: hsl(221.0, 83.0, 53.0).lighten(0.2),
|
||||
list: hsl(0.0, 0.0, 8.0),
|
||||
list_active: hsl(240.0, 3.7, 15.0).opacity(0.2),
|
||||
list_active_border: hsl(240.0, 5.9, 35.5),
|
||||
list_even: hsl(240.0, 3.7, 10.0),
|
||||
list_head: hsl(0.0, 0.0, 8.0),
|
||||
list_hover: hsl(240.0, 3.7, 15.9),
|
||||
muted: hsl(240.0, 3.7, 15.9),
|
||||
muted_foreground: hsl(240.0, 5.0, 64.9),
|
||||
popover: hsl(0.0, 0.0, 10.),
|
||||
popover_foreground: hsl(0.0, 0.0, 78.0),
|
||||
primary: hsl(223.0, 0.0, 98.0),
|
||||
primary_active: hsl(223.0, 0.0, 80.0),
|
||||
primary_foreground: hsl(223.0, 5.9, 10.0),
|
||||
primary_hover: hsl(223.0, 0.0, 90.0),
|
||||
progress_bar: hsl(223.0, 0.0, 98.0),
|
||||
ring: hsl(240.0, 4.9, 83.9),
|
||||
scrollbar: hsl(240., 1., 15.).opacity(0.75),
|
||||
scrollbar_thumb: hsl(0., 0., 48.).opacity(0.9),
|
||||
scrollbar_thumb_hover: hsl(0., 0., 68.),
|
||||
secondary: hsl(240.0, 0., 13.0),
|
||||
secondary_active: hsl(240.0, 0., 10.),
|
||||
secondary_foreground: hsl(0.0, 0.0, 78.0),
|
||||
secondary_hover: hsl(240.0, 0., 15.),
|
||||
selection: hsl(211.0, 97.0, 22.0),
|
||||
skeleton: hsla(223.0, 0.0, 98.0, 0.1),
|
||||
slider_bar: hsl(223.0, 0.0, 98.0),
|
||||
slider_thumb: hsl(0.0, 0.0, 8.0),
|
||||
tab: transparent_black(),
|
||||
tab_active: hsl(0.0, 0.0, 8.0),
|
||||
tab_active_foreground: hsl(0., 0., 78.),
|
||||
tab_bar: hsl(299.0, 0., 5.5),
|
||||
tab_foreground: hsl(0., 0., 78.),
|
||||
title_bar: hsl(240.0, 0.0, 10.0),
|
||||
title_bar_border: hsl(240.0, 3.7, 15.9),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Colorize {
|
||||
fn opacity(&self, opacity: f32) -> Hsla;
|
||||
fn divide(&self, divisor: f32) -> Hsla;
|
||||
fn invert(&self) -> Hsla;
|
||||
fn invert_l(&self) -> Hsla;
|
||||
fn lighten(&self, amount: f32) -> Hsla;
|
||||
fn darken(&self, amount: f32) -> Hsla;
|
||||
fn apply(&self, base_color: Hsla) -> Hsla;
|
||||
}
|
||||
|
||||
impl Colorize for Hsla {
|
||||
/// Returns a new color with the given opacity.
|
||||
///
|
||||
/// The opacity is a value between 0.0 and 1.0, where 0.0 is fully transparent and 1.0 is fully opaque.
|
||||
fn opacity(&self, factor: f32) -> Hsla {
|
||||
Hsla {
|
||||
a: self.a * factor.clamp(0.0, 1.0),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new color with each channel divided by the given divisor.
|
||||
///
|
||||
/// The divisor in range of 0.0 .. 1.0
|
||||
fn divide(&self, divisor: f32) -> Hsla {
|
||||
Hsla {
|
||||
a: divisor,
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Return inverted color
|
||||
fn invert(&self) -> Hsla {
|
||||
Hsla {
|
||||
h: (self.h + 1.8) % 3.6,
|
||||
s: 1.0 - self.s,
|
||||
l: 1.0 - self.l,
|
||||
a: self.a,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return inverted lightness
|
||||
fn invert_l(&self) -> Hsla {
|
||||
Hsla {
|
||||
l: 1.0 - self.l,
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a new color with the lightness increased by the given factor.
|
||||
///
|
||||
/// factor range: 0.0 .. 1.0
|
||||
fn lighten(&self, factor: f32) -> Hsla {
|
||||
let l = self.l * (1.0 + factor.clamp(0.0, 1.0));
|
||||
|
||||
Hsla { l, ..*self }
|
||||
}
|
||||
|
||||
/// Return a new color with the darkness increased by the given factor.
|
||||
///
|
||||
/// factor range: 0.0 .. 1.0
|
||||
fn darken(&self, factor: f32) -> Hsla {
|
||||
let l = self.l * (1.0 - factor.clamp(0.0, 1.0));
|
||||
|
||||
Hsla { l, ..*self }
|
||||
}
|
||||
|
||||
/// Return a new color with the same lightness and alpha but different hue and saturation.
|
||||
fn apply(&self, new_color: Hsla) -> Hsla {
|
||||
Hsla {
|
||||
h: new_color.h,
|
||||
s: new_color.s,
|
||||
l: self.l,
|
||||
a: self.a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ActiveTheme {
|
||||
fn theme(&self) -> &Theme;
|
||||
}
|
||||
|
||||
impl ActiveTheme for AppContext {
|
||||
fn theme(&self) -> &Theme {
|
||||
Theme::global(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ActiveTheme for ViewContext<'_, V> {
|
||||
fn theme(&self) -> &Theme {
|
||||
self.deref().theme()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ActiveTheme for ModelContext<'_, V> {
|
||||
fn theme(&self) -> &Theme {
|
||||
self.deref().theme()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveTheme for WindowContext<'_> {
|
||||
fn theme(&self) -> &Theme {
|
||||
self.deref().theme()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
Theme::sync_system_appearance(cx)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Theme {
|
||||
pub colors: ThemeColors,
|
||||
pub mode: ThemeMode,
|
||||
pub font_family: SharedString,
|
||||
pub font_size: f32,
|
||||
pub radius: f32,
|
||||
pub shadow: bool,
|
||||
pub transparent: Hsla,
|
||||
/// Show the scrollbar mode, default: Scrolling
|
||||
pub scrollbar_show: ScrollbarShow,
|
||||
}
|
||||
|
||||
impl Deref for Theme {
|
||||
type Target = ThemeColors;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.colors
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Theme {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.colors
|
||||
}
|
||||
}
|
||||
|
||||
impl Global for Theme {}
|
||||
|
||||
impl Theme {
|
||||
/// Returns the global theme reference
|
||||
pub fn global(cx: &AppContext) -> &Theme {
|
||||
cx.global::<Theme>()
|
||||
}
|
||||
|
||||
/// Returns the global theme mutable reference
|
||||
pub fn global_mut(cx: &mut AppContext) -> &mut Theme {
|
||||
cx.global_mut::<Theme>()
|
||||
}
|
||||
|
||||
/// Apply a mask color to the theme.
|
||||
pub fn apply_color(&mut self, mask_color: Hsla) {
|
||||
self.title_bar = self.title_bar.apply(mask_color);
|
||||
self.title_bar_border = self.title_bar_border.apply(mask_color);
|
||||
self.background = self.background.apply(mask_color);
|
||||
self.foreground = self.foreground.apply(mask_color);
|
||||
self.card = self.card.apply(mask_color);
|
||||
self.card_foreground = self.card_foreground.apply(mask_color);
|
||||
self.popover = self.popover.apply(mask_color);
|
||||
self.popover_foreground = self.popover_foreground.apply(mask_color);
|
||||
self.primary = self.primary.apply(mask_color);
|
||||
self.primary_hover = self.primary_hover.apply(mask_color);
|
||||
self.primary_active = self.primary_active.apply(mask_color);
|
||||
self.primary_foreground = self.primary_foreground.apply(mask_color);
|
||||
self.secondary = self.secondary.apply(mask_color);
|
||||
self.secondary_hover = self.secondary_hover.apply(mask_color);
|
||||
self.secondary_active = self.secondary_active.apply(mask_color);
|
||||
self.secondary_foreground = self.secondary_foreground.apply(mask_color);
|
||||
self.muted = self.muted.apply(mask_color);
|
||||
self.muted_foreground = self.muted_foreground.apply(mask_color);
|
||||
self.accent = self.accent.apply(mask_color);
|
||||
self.accent_foreground = self.accent_foreground.apply(mask_color);
|
||||
self.border = self.border.apply(mask_color);
|
||||
self.input = self.input.apply(mask_color);
|
||||
self.ring = self.ring.apply(mask_color);
|
||||
self.scrollbar = self.scrollbar.apply(mask_color);
|
||||
self.scrollbar_thumb = self.scrollbar_thumb.apply(mask_color);
|
||||
self.scrollbar_thumb_hover = self.scrollbar_thumb_hover.apply(mask_color);
|
||||
self.drag_border = self.drag_border.apply(mask_color);
|
||||
self.drop_target = self.drop_target.apply(mask_color);
|
||||
self.tab_bar = self.tab_bar.apply(mask_color);
|
||||
self.tab = self.tab.apply(mask_color);
|
||||
self.tab_active = self.tab_active.apply(mask_color);
|
||||
self.tab_foreground = self.tab_foreground.apply(mask_color);
|
||||
self.tab_active_foreground = self.tab_active_foreground.apply(mask_color);
|
||||
self.progress_bar = self.progress_bar.apply(mask_color);
|
||||
self.slider_bar = self.slider_bar.apply(mask_color);
|
||||
self.slider_thumb = self.slider_thumb.apply(mask_color);
|
||||
self.list = self.list.apply(mask_color);
|
||||
self.list_even = self.list_even.apply(mask_color);
|
||||
self.list_head = self.list_head.apply(mask_color);
|
||||
self.list_active = self.list_active.apply(mask_color);
|
||||
self.list_active_border = self.list_active_border.apply(mask_color);
|
||||
self.list_hover = self.list_hover.apply(mask_color);
|
||||
self.link = self.link.apply(mask_color);
|
||||
self.link_hover = self.link_hover.apply(mask_color);
|
||||
self.link_active = self.link_active.apply(mask_color);
|
||||
self.skeleton = self.skeleton.apply(mask_color);
|
||||
self.title_bar = self.title_bar.apply(mask_color);
|
||||
self.title_bar_border = self.title_bar_border.apply(mask_color);
|
||||
}
|
||||
|
||||
/// Sync the theme with the system appearance
|
||||
pub fn sync_system_appearance(cx: &mut AppContext) {
|
||||
match cx.window_appearance() {
|
||||
WindowAppearance::Dark | WindowAppearance::VibrantDark => {
|
||||
Self::change(ThemeMode::Dark, cx)
|
||||
}
|
||||
WindowAppearance::Light | WindowAppearance::VibrantLight => {
|
||||
Self::change(ThemeMode::Light, cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change(mode: ThemeMode, cx: &mut AppContext) {
|
||||
let colors = match mode {
|
||||
ThemeMode::Light => ThemeColors::light(),
|
||||
ThemeMode::Dark => ThemeColors::dark(),
|
||||
};
|
||||
|
||||
let mut theme = Theme::from(colors);
|
||||
theme.mode = mode;
|
||||
|
||||
cx.set_global(theme);
|
||||
cx.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ThemeColors> for Theme {
|
||||
fn from(colors: ThemeColors) -> Self {
|
||||
Theme {
|
||||
mode: ThemeMode::default(),
|
||||
transparent: Hsla::transparent_black(),
|
||||
font_size: 16.0,
|
||||
font_family: if cfg!(target_os = "macos") {
|
||||
".SystemUIFont".into()
|
||||
} else if cfg!(target_os = "windows") {
|
||||
"Segoe UI".into()
|
||||
} else {
|
||||
"FreeMono".into()
|
||||
},
|
||||
radius: 6.0,
|
||||
shadow: false,
|
||||
scrollbar_show: ScrollbarShow::default(),
|
||||
colors,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, PartialOrd, Eq)]
|
||||
pub enum ThemeMode {
|
||||
#[default]
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
impl ThemeMode {
|
||||
pub fn is_dark(&self) -> bool {
|
||||
matches!(self, Self::Dark)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
use crate::theme::{ActiveTheme, ThemeMode};
|
||||
use gpui::{AppContext, Hsla, SharedString};
|
||||
|
||||
/// A collection of colors that are used to style the UI.
|
||||
///
|
||||
/// Each step has a semantic meaning, and is used to style different parts of the UI.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub struct ColorScaleStep(usize);
|
||||
|
||||
impl ColorScaleStep {
|
||||
pub const ONE: Self = Self(1);
|
||||
pub const TWO: Self = Self(2);
|
||||
pub const THREE: Self = Self(3);
|
||||
pub const FOUR: Self = Self(4);
|
||||
pub const FIVE: Self = Self(5);
|
||||
pub const SIX: Self = Self(6);
|
||||
pub const SEVEN: Self = Self(7);
|
||||
pub const EIGHT: Self = Self(8);
|
||||
pub const NINE: Self = Self(9);
|
||||
pub const TEN: Self = Self(10);
|
||||
pub const ELEVEN: Self = Self(11);
|
||||
pub const TWELVE: Self = Self(12);
|
||||
|
||||
/// All of the steps in a [`ColorScale`].
|
||||
pub const ALL: [ColorScaleStep; 12] = [
|
||||
Self::ONE,
|
||||
Self::TWO,
|
||||
Self::THREE,
|
||||
Self::FOUR,
|
||||
Self::FIVE,
|
||||
Self::SIX,
|
||||
Self::SEVEN,
|
||||
Self::EIGHT,
|
||||
Self::NINE,
|
||||
Self::TEN,
|
||||
Self::ELEVEN,
|
||||
Self::TWELVE,
|
||||
];
|
||||
}
|
||||
|
||||
/// A scale of colors for a given [`ColorScaleSet`].
|
||||
///
|
||||
/// Each [`ColorScale`] contains exactly 12 colors. Refer to
|
||||
/// [`ColorScaleStep`] for a reference of what each step is used for.
|
||||
pub struct ColorScale(Vec<Hsla>);
|
||||
|
||||
impl FromIterator<Hsla> for ColorScale {
|
||||
fn from_iter<T: IntoIterator<Item = Hsla>>(iter: T) -> Self {
|
||||
Self(Vec::from_iter(iter))
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorScale {
|
||||
/// Returns the specified step in the [`ColorScale`].
|
||||
#[inline]
|
||||
pub fn step(&self, step: ColorScaleStep) -> Hsla {
|
||||
// Steps are one-based, so we need convert to the zero-based vec index.
|
||||
self.0[step.0 - 1]
|
||||
}
|
||||
|
||||
/// `Step 1` - Used for main application backgrounds.
|
||||
///
|
||||
/// This step provides a neutral base for any overlaying components, ideal for applications' main backdrop or empty spaces such as canvas areas.
|
||||
///
|
||||
#[inline]
|
||||
pub fn step_1(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::ONE)
|
||||
}
|
||||
|
||||
/// `Step 2` - Used for both main application backgrounds and subtle component backgrounds.
|
||||
///
|
||||
/// Like `Step 1`, this step allows variations in background styles, from striped tables, sidebar backgrounds, to card backgrounds.
|
||||
#[inline]
|
||||
pub fn step_2(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::TWO)
|
||||
}
|
||||
|
||||
/// `Step 3` - Used for UI component backgrounds in their normal states.
|
||||
///
|
||||
/// This step maintains accessibility by guaranteeing a contrast ratio of 4.5:1 with steps 11 and 12 for text. It could also suit hover states for transparent components.
|
||||
#[inline]
|
||||
pub fn step_3(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::THREE)
|
||||
}
|
||||
|
||||
/// `Step 4` - Used for UI component backgrounds in their hover states.
|
||||
///
|
||||
/// Also suited for pressed or selected states of components with a transparent background.
|
||||
#[inline]
|
||||
pub fn step_4(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::FOUR)
|
||||
}
|
||||
|
||||
/// `Step 5` - Used for UI component backgrounds in their pressed or selected states.
|
||||
#[inline]
|
||||
pub fn step_5(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::FIVE)
|
||||
}
|
||||
|
||||
/// `Step 6` - Used for subtle borders on non-interactive components.
|
||||
///
|
||||
/// Its usage spans from sidebars' borders, headers' dividers, cards' outlines, to alerts' edges and separators.
|
||||
#[inline]
|
||||
pub fn step_6(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::SIX)
|
||||
}
|
||||
|
||||
/// `Step 7` - Used for subtle borders on interactive components.
|
||||
///
|
||||
/// This step subtly delineates the boundary of elements users interact with.
|
||||
#[inline]
|
||||
pub fn step_7(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::SEVEN)
|
||||
}
|
||||
|
||||
/// `Step 8` - Used for stronger borders on interactive components and focus rings.
|
||||
///
|
||||
/// It strengthens the visibility and accessibility of active elements and their focus states.
|
||||
#[inline]
|
||||
pub fn step_8(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::EIGHT)
|
||||
}
|
||||
|
||||
/// `Step 9` - Used for solid backgrounds.
|
||||
///
|
||||
/// `Step 9` is the most saturated step, having the least mix of white or black.
|
||||
///
|
||||
/// Due to its high chroma, `Step 9` is versatile and particularly useful for semantic colors such as
|
||||
/// error, warning, and success indicators.
|
||||
#[inline]
|
||||
pub fn step_9(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::NINE)
|
||||
}
|
||||
|
||||
/// `Step 10` - Used for hovered or active solid backgrounds, particularly when `Step 9` is their normal state.
|
||||
///
|
||||
/// May also be used for extremely low contrast text. This should be used sparingly, as it may be difficult to read.
|
||||
#[inline]
|
||||
pub fn step_10(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::TEN)
|
||||
}
|
||||
|
||||
/// `Step 11` - Used for text and icons requiring low contrast or less emphasis.
|
||||
#[inline]
|
||||
pub fn step_11(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::ELEVEN)
|
||||
}
|
||||
|
||||
/// `Step 12` - Used for text and icons requiring high contrast or prominence.
|
||||
#[inline]
|
||||
pub fn step_12(&self) -> Hsla {
|
||||
self.step(ColorScaleStep::TWELVE)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ColorScales {
|
||||
pub gray: ColorScaleSet,
|
||||
pub mauve: ColorScaleSet,
|
||||
pub slate: ColorScaleSet,
|
||||
pub sage: ColorScaleSet,
|
||||
pub olive: ColorScaleSet,
|
||||
pub sand: ColorScaleSet,
|
||||
pub gold: ColorScaleSet,
|
||||
pub bronze: ColorScaleSet,
|
||||
pub brown: ColorScaleSet,
|
||||
pub yellow: ColorScaleSet,
|
||||
pub amber: ColorScaleSet,
|
||||
pub orange: ColorScaleSet,
|
||||
pub tomato: ColorScaleSet,
|
||||
pub red: ColorScaleSet,
|
||||
pub ruby: ColorScaleSet,
|
||||
pub crimson: ColorScaleSet,
|
||||
pub pink: ColorScaleSet,
|
||||
pub plum: ColorScaleSet,
|
||||
pub purple: ColorScaleSet,
|
||||
pub violet: ColorScaleSet,
|
||||
pub iris: ColorScaleSet,
|
||||
pub indigo: ColorScaleSet,
|
||||
pub blue: ColorScaleSet,
|
||||
pub cyan: ColorScaleSet,
|
||||
pub teal: ColorScaleSet,
|
||||
pub jade: ColorScaleSet,
|
||||
pub green: ColorScaleSet,
|
||||
pub grass: ColorScaleSet,
|
||||
pub lime: ColorScaleSet,
|
||||
pub mint: ColorScaleSet,
|
||||
pub sky: ColorScaleSet,
|
||||
pub black: ColorScaleSet,
|
||||
pub white: ColorScaleSet,
|
||||
}
|
||||
|
||||
impl IntoIterator for ColorScales {
|
||||
type Item = ColorScaleSet;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
vec![
|
||||
self.gray,
|
||||
self.mauve,
|
||||
self.slate,
|
||||
self.sage,
|
||||
self.olive,
|
||||
self.sand,
|
||||
self.gold,
|
||||
self.bronze,
|
||||
self.brown,
|
||||
self.yellow,
|
||||
self.amber,
|
||||
self.orange,
|
||||
self.tomato,
|
||||
self.red,
|
||||
self.ruby,
|
||||
self.crimson,
|
||||
self.pink,
|
||||
self.plum,
|
||||
self.purple,
|
||||
self.violet,
|
||||
self.iris,
|
||||
self.indigo,
|
||||
self.blue,
|
||||
self.cyan,
|
||||
self.teal,
|
||||
self.jade,
|
||||
self.green,
|
||||
self.grass,
|
||||
self.lime,
|
||||
self.mint,
|
||||
self.sky,
|
||||
self.black,
|
||||
self.white,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides groups of [`ColorScale`]s for light and dark themes, as well as transparent versions of each scale.
|
||||
pub struct ColorScaleSet {
|
||||
name: SharedString,
|
||||
light: ColorScale,
|
||||
dark: ColorScale,
|
||||
light_alpha: ColorScale,
|
||||
dark_alpha: ColorScale,
|
||||
}
|
||||
|
||||
impl ColorScaleSet {
|
||||
pub fn new(
|
||||
name: impl Into<SharedString>,
|
||||
light: ColorScale,
|
||||
light_alpha: ColorScale,
|
||||
dark: ColorScale,
|
||||
dark_alpha: ColorScale,
|
||||
) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
light,
|
||||
light_alpha,
|
||||
dark,
|
||||
dark_alpha,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &SharedString {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn light(&self) -> &ColorScale {
|
||||
&self.light
|
||||
}
|
||||
|
||||
pub fn light_alpha(&self) -> &ColorScale {
|
||||
&self.light_alpha
|
||||
}
|
||||
|
||||
pub fn dark(&self) -> &ColorScale {
|
||||
&self.dark
|
||||
}
|
||||
|
||||
pub fn dark_alpha(&self) -> &ColorScale {
|
||||
&self.dark_alpha
|
||||
}
|
||||
|
||||
pub fn step(&self, cx: &AppContext, step: ColorScaleStep) -> Hsla {
|
||||
match cx.theme().mode {
|
||||
ThemeMode::Light => self.light().step(step),
|
||||
ThemeMode::Dark => self.dark().step(step),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step_alpha(&self, cx: &AppContext, step: ColorScaleStep) -> Hsla {
|
||||
match cx.theme().mode {
|
||||
ThemeMode::Light => self.light_alpha.step(step),
|
||||
ThemeMode::Dark => self.dark_alpha.step(step),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user