This commit is contained in:
2026-10-08 08:42:44 +07:00
parent 069f031af9
commit 2efb6ac5ca
24 changed files with 628 additions and 2614 deletions
+281
View File
@@ -0,0 +1,281 @@
#![allow(dead_code)] // transitional: scaffold fields die in Phase 5, unconsumed roles live on
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))
}
#[derive(Debug, Clone, Copy)]
pub struct ResolvedAccentRoles {
pub primary: Hsla,
pub strong: Hsla,
pub wash: Hsla,
pub on: Hsla,
pub selection: Hsla,
pub caret: Hsla,
pub activity: Hsla,
pub glyph: [Hsla; 3],
pub hover: Hsla,
pub active: Hsla,
pub selected: Hsla,
/// Accent text guaranteed 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),
caret: hsla(accent.caret),
activity: hsla(accent.activity),
glyph: [
hsla(accent.glyph[0]),
hsla(accent.glyph[1]),
hsla(accent.glyph[2]),
],
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 whenever the active
/// variant, accent, or appearance changes.
///
/// The fields after `diff_hunk` are a transitional scaffold (D6): they keep the
/// removed role names alive — computed from zeron roles — so the ~51 downstream
/// files keep compiling until the Phase 3 rewrite retires them, one by one.
/// Everything below `drop_target_background` is deleted in Phase 5.
#[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,
// Transitional scaffold — delete in Phase 5.
pub surface_background: Hsla,
pub elevated_surface_background: Hsla,
pub panel_background: Hsla,
pub border_variant: Hsla,
pub border_focused: Hsla,
pub border_selected: Hsla,
pub border_transparent: Hsla,
pub ring: Hsla,
pub selection: Hsla,
pub text_placeholder: Hsla,
pub text_accent: Hsla,
pub text_danger: Hsla,
pub text_warning: Hsla,
pub icon: Hsla,
pub icon_muted: Hsla,
pub icon_accent: Hsla,
pub element_background: Hsla,
pub element_foreground: Hsla,
pub element_hover: Hsla,
pub element_active: Hsla,
pub element_selected: Hsla,
pub element_disabled: Hsla,
pub secondary_background: Hsla,
pub secondary_foreground: Hsla,
pub secondary_hover: Hsla,
pub secondary_active: Hsla,
pub secondary_selected: Hsla,
pub secondary_disabled: Hsla,
pub danger_foreground: Hsla,
pub danger_background: Hsla,
pub danger_hover: Hsla,
pub danger_active: Hsla,
pub danger_selected: Hsla,
pub danger_disabled: Hsla,
pub warning_foreground: Hsla,
pub warning_background: Hsla,
pub warning_hover: Hsla,
pub warning_active: Hsla,
pub warning_selected: Hsla,
pub warning_disabled: Hsla,
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,
pub tab_background: Hsla,
pub tab_foreground: Hsla,
pub tab_hover_background: Hsla,
pub tab_active_background: Hsla,
pub tab_active_foreground: Hsla,
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,
pub drop_target_background: Hsla,
}
impl ResolvedColors {
pub fn resolve(variant: &ThemeVariant, accent: &AccentRoles) -> Self {
let colors = variant.colors.clone();
let ThemeColors {
background,
shell,
raised,
card,
dialog,
overlay,
hover,
active,
border,
border_strong,
text,
text_muted,
text_faint,
solid,
on_solid,
danger,
danger_muted,
warning,
warning_muted,
success,
success_muted,
input,
cursor,
diff_add,
diff_delete,
diff_hunk,
} = colors;
let transparent = Color::rgba(0, 0, 0, 0);
let danger_tint = danger_muted;
let warning_tint = warning_muted;
Self {
background: hsla(background),
shell: hsla(shell),
raised: hsla(raised),
card: hsla(card),
dialog: hsla(dialog),
overlay: hsla(overlay),
hover: hsla(hover),
active: hsla(active),
border: hsla(border),
border_strong: hsla(border_strong),
text: hsla(text),
text_muted: hsla(text_muted),
text_faint: hsla(text_faint),
solid: hsla(solid),
on_solid: hsla(on_solid),
danger: hsla(danger),
danger_muted: hsla(danger_muted),
warning: hsla(warning),
warning_muted: hsla(warning_muted),
success: hsla(success),
success_muted: hsla(success_muted),
input: hsla(input),
cursor: hsla(cursor),
diff_add: hsla(diff_add),
diff_delete: hsla(diff_delete),
diff_hunk: hsla(diff_hunk),
surface_background: hsla(shell),
elevated_surface_background: hsla(raised),
panel_background: hsla(shell),
border_variant: hsla(border),
border_focused: hsla(accent.primary),
border_selected: hsla(accent.primary),
border_transparent: hsla(transparent),
ring: hsla(accent.primary),
selection: hsla(accent.selection),
text_placeholder: hsla(text_faint),
text_accent: hsla(accent.primary),
text_danger: hsla(danger),
text_warning: hsla(warning),
icon: hsla(text_muted),
icon_muted: hsla(text_faint),
icon_accent: hsla(accent.primary),
element_background: hsla(accent.primary),
element_foreground: hsla(accent.on),
element_hover: hsla(accent.primary.mix(background, 0.12)),
element_active: hsla(accent.primary.mix(background, 0.2)),
element_selected: hsla(accent.primary.mix(background, 0.28)),
element_disabled: hsla(accent.primary.with_alpha(0.3)),
secondary_background: hsla(accent.wash),
secondary_foreground: hsla(
accent
.primary
.ensure_contrast(accent.wash.blend_over(background), 4.5),
),
secondary_hover: hsla(accent.selection),
secondary_active: hsla(accent.selection),
secondary_selected: hsla(accent.selection),
secondary_disabled: hsla(accent.wash.with_alpha(0.5)),
danger_foreground: hsla(danger.ensure_contrast(danger_tint, 4.5)),
danger_background: hsla(danger_tint),
danger_hover: hsla(danger.with_alpha(0.15)),
danger_active: hsla(danger.with_alpha(0.25)),
danger_selected: hsla(danger.with_alpha(0.25)),
danger_disabled: hsla(danger.with_alpha(0.12)),
warning_foreground: hsla(warning.ensure_contrast(warning_tint, 4.5)),
warning_background: hsla(warning_tint),
warning_hover: hsla(warning.with_alpha(0.15)),
warning_active: hsla(warning.with_alpha(0.25)),
warning_selected: hsla(warning.with_alpha(0.25)),
warning_disabled: hsla(warning.with_alpha(0.12)),
ghost_element_background: hsla(transparent),
ghost_element_background_alt: hsla(raised),
ghost_element_hover: hsla(hover),
ghost_element_active: hsla(active),
ghost_element_selected: hsla(active),
ghost_element_disabled: hsla(border.with_alpha(0.4)),
tab_background: hsla(shell),
tab_foreground: hsla(text_muted),
tab_hover_background: hsla(hover),
tab_active_background: hsla(background),
tab_active_foreground: hsla(text),
scrollbar_thumb_background: hsla(border.with_alpha(0.7)),
scrollbar_thumb_hover_background: hsla(border_strong),
scrollbar_thumb_border: hsla(transparent),
scrollbar_track_background: hsla(transparent),
scrollbar_track_border: hsla(border),
drop_target_background: hsla(accent.selection),
}
}
}