2026-04-20 15:13:26 +01:00
|
|
|
use gpui::Rgba;
|
|
|
|
|
|
|
|
|
|
use crate::colors::{amber, hex, neutral, red, violet};
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
|
|
|
pub enum ThemeMode {
|
|
|
|
|
Light,
|
|
|
|
|
#[default]
|
|
|
|
|
Dark,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub struct Theme {
|
|
|
|
|
pub id: &'static str,
|
|
|
|
|
pub name: &'static str,
|
|
|
|
|
pub mode: ThemeMode,
|
|
|
|
|
pub colors: ThemeColors,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Theme {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Variant::default().theme()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub struct ThemeColors {
|
|
|
|
|
pub background: Rgba,
|
|
|
|
|
pub surface: Rgba,
|
|
|
|
|
pub surface_elevated: Rgba,
|
|
|
|
|
pub border: Rgba,
|
|
|
|
|
pub text: Rgba,
|
|
|
|
|
pub text_muted: Rgba,
|
|
|
|
|
pub accent: Rgba,
|
|
|
|
|
pub accent_hover: Rgba,
|
|
|
|
|
pub accent_text: Rgba,
|
|
|
|
|
pub success: Rgba,
|
|
|
|
|
pub warning: Rgba,
|
|
|
|
|
pub danger: Rgba,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub enum Variant {
|
|
|
|
|
VioletLight,
|
|
|
|
|
#[default]
|
|
|
|
|
VioletDark,
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-23 11:18:43 +01:00
|
|
|
pub(crate) fn current(cx: &gpui::App) -> &Theme {
|
|
|
|
|
cx.global::<Theme>()
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-20 15:13:26 +01:00
|
|
|
impl Variant {
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub const ALL: [Self; 2] = [Self::VioletLight, Self::VioletDark];
|
|
|
|
|
|
|
|
|
|
pub const fn label(self) -> &'static str {
|
|
|
|
|
match self {
|
|
|
|
|
Self::VioletLight => "Violet Light",
|
|
|
|
|
Self::VioletDark => "Violet Dark",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub const fn theme(self) -> Theme {
|
|
|
|
|
match self {
|
|
|
|
|
Self::VioletLight => Theme {
|
|
|
|
|
id: "violet-light",
|
|
|
|
|
name: "Violet Light",
|
|
|
|
|
mode: ThemeMode::Light,
|
|
|
|
|
colors: ThemeColors {
|
|
|
|
|
background: neutral(50),
|
|
|
|
|
surface: neutral(100),
|
|
|
|
|
surface_elevated: neutral(200),
|
|
|
|
|
border: neutral(200),
|
|
|
|
|
text: neutral(900),
|
|
|
|
|
text_muted: neutral(600),
|
|
|
|
|
accent: violet(600),
|
|
|
|
|
accent_hover: violet(500),
|
|
|
|
|
accent_text: neutral(100),
|
|
|
|
|
success: hex(0x16a34a),
|
|
|
|
|
warning: amber(600),
|
|
|
|
|
danger: red(600),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Self::VioletDark => Theme {
|
|
|
|
|
id: "violet-dark",
|
|
|
|
|
name: "Violet Dark",
|
|
|
|
|
mode: ThemeMode::Dark,
|
|
|
|
|
colors: ThemeColors {
|
|
|
|
|
background: neutral(950),
|
|
|
|
|
surface: neutral(900),
|
|
|
|
|
surface_elevated: neutral(800),
|
|
|
|
|
border: neutral(800),
|
|
|
|
|
text: neutral(50),
|
|
|
|
|
text_muted: neutral(400),
|
2026-04-21 11:50:04 +01:00
|
|
|
accent: violet(600),
|
2026-04-20 15:13:26 +01:00
|
|
|
accent_hover: violet(300),
|
|
|
|
|
accent_text: neutral(100),
|
|
|
|
|
success: hex(0x22c55e),
|
|
|
|
|
warning: amber(500),
|
|
|
|
|
danger: red(500),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<gpui::WindowAppearance> for Theme {
|
|
|
|
|
fn from(value: gpui::WindowAppearance) -> Self {
|
|
|
|
|
let variant = match value {
|
|
|
|
|
gpui::WindowAppearance::Light | gpui::WindowAppearance::VibrantLight => {
|
|
|
|
|
Variant::VioletLight
|
|
|
|
|
}
|
|
|
|
|
gpui::WindowAppearance::Dark | gpui::WindowAppearance::VibrantDark => {
|
|
|
|
|
Variant::VioletDark
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
variant.theme()
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-23 11:18:43 +01:00
|
|
|
|
|
|
|
|
impl gpui::Global for Theme {}
|