theme: Export more theme options for schema. (#1442)

- Fix theme switch to support other UI settings (e.g.: radius, shadow,
font_size).
- Update `matrix` theme to use rounded 0px.

<img width="1380" height="1139" alt="image"
src="https://github.com/user-attachments/assets/24832fde-5b5e-4508-9b38-6c3c2890aedb"
/>
This commit is contained in:
Jason Lee 2025-10-28 11:28:18 +08:00 committed by GitHub
parent cc0f936348
commit 904c9f3fa7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 85 additions and 18 deletions

View file

@ -25,6 +25,26 @@
"format": "float", "format": "float",
"default": null "default": null
}, },
"font.family": {
"description": "The base font family, default is system font: `.SystemUIFont`.",
"type": ["string", "null"],
"default": null
},
"radius": {
"description": "The border radius for general elements, default is 6.",
"type": ["number", "null"],
"default": null
},
"radius.lg": {
"description": "The border radius for large elements like Modals and Notifications, default is 8.",
"type": ["number", "null"],
"default": null
},
"shadow": {
"description": "Set shadows in the theme, for example the Input and Button, default is true.",
"type": ["boolean", "null"],
"default": null
},
"themes": { "themes": {
"type": "array", "type": "array",
"items": { "items": {

View file

@ -413,7 +413,7 @@ impl Styled for StorySection {
} }
impl RenderOnce for StorySection { impl RenderOnce for StorySection {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement { fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
GroupBox::new() GroupBox::new()
.outline() .outline()
.title( .title(
@ -426,7 +426,7 @@ impl RenderOnce for StorySection {
) )
.content_style( .content_style(
StyleRefinement::default() StyleRefinement::default()
.rounded_lg() .rounded(cx.theme().radius_lg)
.overflow_x_hidden() .overflow_x_hidden()
.items_center() .items_center()
.justify_center(), .justify_center(),

View file

@ -214,8 +214,10 @@ impl Render for Gallery {
.child( .child(
div() div()
.bg(cx.theme().sidebar_accent) .bg(cx.theme().sidebar_accent)
.px_1()
.rounded_full() .rounded_full()
.when(cx.theme().radius.is_zero(), |this| {
this.rounded(px(0.))
})
.flex_1() .flex_1()
.mx_1() .mx_1()
.child( .child(

View file

@ -9,8 +9,8 @@ use crate::{ActiveTheme, AxisExt};
use gpui::{ use gpui::{
fill, point, px, relative, size, App, Axis, BorderStyle, Bounds, ContentMask, Corner, fill, point, px, relative, size, App, Axis, BorderStyle, Bounds, ContentMask, Corner,
CursorStyle, Edges, Element, GlobalElementId, Hitbox, HitboxBehavior, Hsla, InspectorElementId, CursorStyle, Edges, Element, GlobalElementId, Hitbox, HitboxBehavior, Hsla, InspectorElementId,
IntoElement, LayoutId, ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, IntoElement, IsZero, LayoutId, ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Size, Style, Timer, PaintQuad, Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Size, Style, Timer,
UniformListScrollHandle, Window, UniformListScrollHandle, Window,
}; };
use schemars::JsonSchema; use schemars::JsonSchema;
@ -728,7 +728,10 @@ impl Element for Scrollbar {
|window| { |window| {
for state in prepaint.states.iter() { for state in prepaint.states.iter() {
let axis = state.axis; let axis = state.axis;
let radius = state.radius; let mut radius = state.radius;
if cx.theme().radius.is_zero() {
radius = px(0.);
}
let bounds = state.bounds; let bounds = state.bounds;
let thumb_bounds = state.thumb_bounds; let thumb_bounds = state.thumb_bounds;
let scroll_area_size = state.scroll_size; let scroll_area_size = state.scroll_size;

View file

@ -64,7 +64,7 @@ pub struct Theme {
impl Default for Theme { impl Default for Theme {
fn default() -> Self { fn default() -> Self {
Self::from(ThemeColor::default()) Self::from(&ThemeColor::default())
} }
} }
@ -181,8 +181,8 @@ impl Theme {
} }
} }
impl From<ThemeColor> for Theme { impl From<&ThemeColor> for Theme {
fn from(colors: ThemeColor) -> Self { fn from(colors: &ThemeColor) -> Self {
Theme { Theme {
mode: ThemeMode::default(), mode: ThemeMode::default(),
transparent: Hsla::transparent_black(), transparent: Hsla::transparent_black(),
@ -201,7 +201,7 @@ impl From<ThemeColor> for Theme {
tile_grid_size: px(8.), tile_grid_size: px(8.),
tile_shadow: true, tile_shadow: true,
tile_radius: px(0.), tile_radius: px(0.),
colors, colors: *colors,
light_theme: Rc::new(ThemeConfig::default()), light_theme: Rc::new(ThemeConfig::default()),
dark_theme: Rc::new(ThemeConfig::default()), dark_theme: Rc::new(ThemeConfig::default()),
highlight_theme: HighlightTheme::default_light(), highlight_theme: HighlightTheme::default_light(),

View file

@ -1,7 +1,7 @@
use std::{rc::Rc, sync::Arc}; use std::{rc::Rc, sync::Arc};
use anyhow::Result; use anyhow::Result;
use gpui::{Hsla, SharedString}; use gpui::{px, Hsla, SharedString};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,10 +21,6 @@ pub struct ThemeSet {
/// The URL of the theme. /// The URL of the theme.
pub url: Option<SharedString>, pub url: Option<SharedString>,
/// The base font size, default is 16.
#[serde(rename = "font.size")]
pub font_size: Option<f32>,
#[serde(rename = "themes")] #[serde(rename = "themes")]
pub themes: Vec<ThemeConfig>, pub themes: Vec<ThemeConfig>,
} }
@ -38,6 +34,24 @@ pub struct ThemeConfig {
pub name: SharedString, pub name: SharedString,
/// The mode of the theme, default is light. /// The mode of the theme, default is light.
pub mode: ThemeMode, pub mode: ThemeMode,
/// The base font size, default is 16.
#[serde(rename = "font.size")]
pub font_size: Option<f32>,
/// The base font family, default is system font: `.SystemUIFont`.
#[serde(rename = "font.family")]
pub font_family: Option<SharedString>,
/// The border radius for general elements, default is 6.
#[serde(rename = "radius")]
pub radius: Option<usize>,
/// The border radius for large elements like Modals and Notifications, default is 8.
#[serde(rename = "radius.lg")]
pub radius_lg: Option<usize>,
/// Set shadows in the theme, for example the Input and Button, default is true.
#[serde(rename = "shadow")]
pub shadow: Option<bool>,
/// The colors of the theme. /// The colors of the theme.
pub colors: ThemeConfigColors, pub colors: ThemeConfigColors,
/// The highlight theme, this part is combilbility with `style` section in Zed theme. /// The highlight theme, this part is combilbility with `style` section in Zed theme.
@ -623,12 +637,38 @@ impl Theme {
} }
let default_theme = if config.mode.is_dark() { let default_theme = if config.mode.is_dark() {
ThemeColor::dark() Self::from(ThemeColor::dark().as_ref())
} else { } else {
ThemeColor::light() Self::from(ThemeColor::light().as_ref())
}; };
self.colors.apply_config(&config, &default_theme); if let Some(font_size) = config.font_size {
self.font_size = px(font_size);
} else {
self.font_size = default_theme.font_size;
}
if let Some(font_family) = &config.font_family {
self.font_family = font_family.clone();
} else {
self.font_family = default_theme.font_family.clone();
}
if let Some(radius) = config.radius {
self.radius = px(radius as f32);
} else {
self.radius = default_theme.radius;
}
if let Some(radius_lg) = config.radius_lg {
self.radius_lg = px(radius_lg as f32);
} else {
self.radius_lg = default_theme.radius_lg;
}
if let Some(shadow) = config.shadow {
self.shadow = shadow;
} else {
self.shadow = default_theme.shadow;
}
self.colors.apply_config(&config, &default_theme.colors);
self.mode = config.mode; self.mode = config.mode;
} }
} }

View file

@ -7,6 +7,8 @@
{ {
"name": "Matrix", "name": "Matrix",
"mode": "dark", "mode": "dark",
"radius": 0,
"radius.lg": 0,
"colors": { "colors": {
"accent.background": "#002d00", "accent.background": "#002d00",
"accent.foreground": "#00FF00", "accent.foreground": "#00FF00",