Files
coop/crates/theme/src/resolved.rs
T
2026-10-08 13:55:23 +07:00

114 lines
3.6 KiB
Rust

use gpui::Hsla;
use crate::model::{AccentRoles, Color, ThemeColors, ThemeVariant};
fn hsla(color: Color) -> Hsla {
let packed = ((color.r as u32) << 24)
| ((color.g as u32) << 16)
| ((color.b as u32) << 8)
| color.a as u32;
Hsla::from(gpui::rgba(packed))
}
/// Accent roles resolved to [`Hsla`], with derived interaction states precomputed.
#[derive(Debug, Clone, Copy)]
pub struct ResolvedAccentRoles {
pub primary: Hsla,
/// Accent for strokes, icons, and text on the background; meets 3:1 contrast.
pub strong: Hsla,
pub wash: Hsla,
pub on: Hsla,
pub selection: Hsla,
pub hover: Hsla,
pub active: Hsla,
pub selected: Hsla,
/// Text guaranteed 4.5:1 readable on `wash`.
pub text_on_wash: Hsla,
/// Text guaranteed readable on the flat `danger` color.
pub on_danger: Hsla,
}
impl ResolvedAccentRoles {
pub fn resolve(accent: &AccentRoles, colors: &ThemeColors) -> Self {
let background = colors.background;
let wash_background = accent.wash.blend_over(background);
Self {
primary: hsla(accent.primary),
strong: hsla(accent.strong),
wash: hsla(accent.wash),
on: hsla(accent.on),
selection: hsla(accent.selection),
hover: hsla(accent.primary.mix(background, 0.12)),
active: hsla(accent.primary.mix(background, 0.2)),
selected: hsla(accent.primary.mix(background, 0.28)),
text_on_wash: hsla(accent.primary.ensure_contrast(wash_background, 4.5)),
on_danger: hsla(colors.danger.best_on_color()),
}
}
}
/// The `Hsla` snapshot components render from, rebuilt on every theme change.
#[derive(Debug, Clone, Copy)]
pub struct ResolvedColors {
pub background: Hsla,
pub shell: Hsla,
pub raised: Hsla,
pub card: Hsla,
pub dialog: Hsla,
pub overlay: Hsla,
pub hover: Hsla,
pub active: Hsla,
pub border: Hsla,
pub border_strong: Hsla,
pub text: Hsla,
pub text_muted: Hsla,
pub text_faint: Hsla,
pub solid: Hsla,
pub on_solid: Hsla,
pub danger: Hsla,
pub danger_muted: Hsla,
pub warning: Hsla,
pub warning_muted: Hsla,
pub success: Hsla,
pub success_muted: Hsla,
pub input: Hsla,
pub cursor: Hsla,
pub diff_add: Hsla,
pub diff_delete: Hsla,
pub diff_hunk: Hsla,
}
impl ResolvedColors {
pub fn resolve(variant: &ThemeVariant) -> Self {
let colors = &variant.colors;
Self {
background: hsla(colors.background),
shell: hsla(colors.shell),
raised: hsla(colors.raised),
card: hsla(colors.card),
dialog: hsla(colors.dialog),
overlay: hsla(colors.overlay),
hover: hsla(colors.hover),
active: hsla(colors.active),
border: hsla(colors.border),
border_strong: hsla(colors.border_strong),
text: hsla(colors.text),
text_muted: hsla(colors.text_muted),
text_faint: hsla(colors.text_faint),
solid: hsla(colors.solid),
on_solid: hsla(colors.on_solid),
danger: hsla(colors.danger),
danger_muted: hsla(colors.danger_muted),
warning: hsla(colors.warning),
warning_muted: hsla(colors.warning_muted),
success: hsla(colors.success),
success_muted: hsla(colors.success_muted),
input: hsla(colors.input),
cursor: hsla(colors.cursor),
diff_add: hsla(colors.diff_add),
diff_delete: hsla(colors.diff_delete),
diff_hunk: hsla(colors.diff_hunk),
}
}
}