This commit is contained in:
2026-10-28 09:34:22 +07:00
parent 823f4b245c
commit b4d3359d4f
29 changed files with 6785 additions and 4 deletions
+68
View File
@@ -0,0 +1,68 @@
//! The theme engine: reads the running system theme and resolves it into the
//! semantic tokens every component paints from.
//!
//! Phase B replaces the bundled light/dark presets with platform adapters
//! (`NSColor` / `UISettings` / portal / Omarchy) behind a `ThemeSource` seam.
mod colors;
pub use colors::ColorTokens;
use gpui::{App, Global, WindowAppearance};
/// Light or dark, resolved from the system appearance.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ThemeVariant {
#[default]
Light,
Dark,
}
impl ThemeVariant {
fn from_appearance(appearance: WindowAppearance) -> Self {
match appearance {
WindowAppearance::Light | WindowAppearance::VibrantLight => Self::Light,
WindowAppearance::Dark | WindowAppearance::VibrantDark => Self::Dark,
}
}
}
/// The resolved theme, installed as the app-wide global.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Theme {
pub variant: ThemeVariant,
pub colors: ColorTokens,
}
impl Global for Theme {}
impl Theme {
/// Reads the theme global. Panics before `init`.
pub fn global(cx: &App) -> &Self {
cx.global::<Self>()
}
pub fn for_variant(variant: ThemeVariant) -> Self {
Self {
variant,
colors: match variant {
ThemeVariant::Light => ColorTokens::light(),
ThemeVariant::Dark => ColorTokens::dark(),
},
}
}
/// Installs the theme global for the current system appearance.
pub fn init(cx: &mut App) {
let variant = ThemeVariant::from_appearance(cx.window_appearance());
cx.set_global(Self::for_variant(variant));
}
/// Re-installs the global when a window's appearance differs from it.
pub fn sync_from_window(window: &gpui::Window, cx: &mut App) {
let variant = ThemeVariant::from_appearance(window.appearance());
if cx.global::<Self>().variant != variant {
cx.set_global(Self::for_variant(variant));
}
}
}