Skip to main content

ui/styles/
palette.rs

1//! Role-based color palette for the design system.
2//!
3//! ## shadcn mapping
4//!
5//! shadcn's `--destructive` / `--destructive-foreground` map to [`danger`]
6//! (Tailwind `red` ramp). Use `danger(600)` for solid destructive backgrounds
7//! and `danger(700)` for hover; pair with white foreground text on filled
8//! destructive controls. Theme-aware neutrals use [`crate::styles::semantic`].
9//!
10//! Colors are organized by semantic ROLE (`neutral`, `primary`, `success`,
11//! `warning`, `danger`, `info`), never by brand color name. Each role is a
12//! `50..=950` shade ramp returning [`Hsla`].
13//!
14//! Hex values are sourced from the Tailwind v3 reference palette internally
15//! (neutral←slate, primary/info←blue, success←green, warning←amber,
16//! danger←red) — but this mapping is an implementation detail. Swapping the
17//! ramps below re-themes every component without touching any call site.
18//!
19//! Accents/status use these swatches directly (mode-agnostic). Neutrals for
20//! surfaces/borders/text should come from [`crate::styles::semantic`] instead,
21//! so dark/light both work via the theme.
22
23use gpui::{Hsla, rgb};
24
25#[inline]
26fn shade(hex: u32) -> Hsla {
27    rgb(hex).into()
28}
29
30/// Neutral ramp (source: Tailwind `slate`). Prefer `semantic::*` for
31/// theme-aware surfaces/text; use this only for fixed neutral swatches.
32pub fn neutral(shade_step: u16) -> Hsla {
33    match shade_step {
34        50 => shade(0xf8fafc),
35        100 => shade(0xf1f5f9),
36        200 => shade(0xe2e8f0),
37        300 => shade(0xcbd5e1),
38        400 => shade(0x94a3b8),
39        500 => shade(0x64748b),
40        600 => shade(0x475569),
41        700 => shade(0x334155),
42        800 => shade(0x1e293b),
43        900 => shade(0x0f172a),
44        950 => shade(0x020617),
45        _ => shade(0x64748b),
46    }
47}
48
49/// Primary accent ramp (source: Tailwind `blue`).
50pub fn primary(shade_step: u16) -> Hsla {
51    match shade_step {
52        50 => shade(0xeff6ff),
53        100 => shade(0xdbeafe),
54        200 => shade(0xbfdbfe),
55        300 => shade(0x93c5fd),
56        400 => shade(0x60a5fa),
57        500 => shade(0x3b82f6),
58        600 => shade(0x2563eb),
59        700 => shade(0x1d4ed8),
60        800 => shade(0x1e40af),
61        900 => shade(0x1e3a8a),
62        950 => shade(0x172554),
63        _ => shade(0x3b82f6),
64    }
65}
66
67/// Informational ramp — shares the primary (blue) ramp.
68pub fn info(shade_step: u16) -> Hsla {
69    primary(shade_step)
70}
71
72/// Success ramp (source: Tailwind `green`).
73pub fn success(shade_step: u16) -> Hsla {
74    match shade_step {
75        50 => shade(0xf0fdf4),
76        100 => shade(0xdcfce7),
77        200 => shade(0xbbf7d0),
78        300 => shade(0x86efac),
79        400 => shade(0x4ade80),
80        500 => shade(0x22c55e),
81        600 => shade(0x16a34a),
82        700 => shade(0x15803d),
83        800 => shade(0x166534),
84        900 => shade(0x14532d),
85        950 => shade(0x052e16),
86        _ => shade(0x22c55e),
87    }
88}
89
90/// Warning ramp (source: Tailwind `amber`).
91pub fn warning(shade_step: u16) -> Hsla {
92    match shade_step {
93        50 => shade(0xfffbeb),
94        100 => shade(0xfef3c7),
95        200 => shade(0xfde68a),
96        300 => shade(0xfcd34d),
97        400 => shade(0xfbbf24),
98        500 => shade(0xf59e0b),
99        600 => shade(0xd97706),
100        700 => shade(0xb45309),
101        800 => shade(0x92400e),
102        900 => shade(0x78350f),
103        950 => shade(0x451a03),
104        _ => shade(0xf59e0b),
105    }
106}
107
108/// Danger/error ramp (source: Tailwind `red`).
109pub fn danger(shade_step: u16) -> Hsla {
110    match shade_step {
111        50 => shade(0xfef2f2),
112        100 => shade(0xfee2e2),
113        200 => shade(0xfecaca),
114        300 => shade(0xfca5a5),
115        400 => shade(0xf87171),
116        500 => shade(0xef4444),
117        600 => shade(0xdc2626),
118        700 => shade(0xb91c1c),
119        800 => shade(0x991b1b),
120        900 => shade(0x7f1d1d),
121        950 => shade(0x450a0a),
122        _ => shade(0xef4444),
123    }
124}