theme: Use font_family for all elements. (#1618)

Close #1613

- And add `mono_font_family` and `mono_font_size` for code editor.
This commit is contained in:
Jason Lee 2025-11-17 11:18:17 +08:00 committed by GitHub
parent 0a5c799aba
commit 6c4de54fa4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 76 additions and 30 deletions

View file

@ -23,27 +23,38 @@
"description": "The base font size, default is 16.", "description": "The base font size, default is 16.",
"type": ["number", "null"], "type": ["number", "null"],
"format": "float", "format": "float",
"default": null "default": 16
}, },
"font.family": { "font.family": {
"description": "The base font family, default is system font: `.SystemUIFont`.", "description": "The base font family, default is system font: `.SystemUIFont`.",
"type": ["string", "null"], "type": ["string", "null"],
"default": ".SystemUIFont"
},
"mono_font.size": {
"description": "The base monospace font size, default is 13.",
"type": ["number", "null"],
"format": "float",
"default": 13
},
"mono_font.family": {
"description": "The monospace font family, default is platform specific:\nmacOS: `Menlo`\n- Windows: `Consolas`\n- Linux: `DejaVu Sans Mono`",
"type": ["string", "null"],
"default": null "default": null
}, },
"radius": { "radius": {
"description": "The border radius for general elements, default is 6.", "description": "The border radius for general elements, default is 6.",
"type": ["number", "null"], "type": ["number", "null"],
"default": null "default": 6
}, },
"radius.lg": { "radius.lg": {
"description": "The border radius for large elements like Dialogs and Notifications, default is 8.", "description": "The border radius for large elements like Dialogs and Notifications, default is 8.",
"type": ["number", "null"], "type": ["number", "null"],
"default": null "default": 8
}, },
"shadow": { "shadow": {
"description": "Set shadows in the theme, for example the Input and Button, default is true.", "description": "Set shadows in the theme, for example the Input and Button, default is true.",
"type": ["boolean", "null"], "type": ["boolean", "null"],
"default": null "default": true
}, },
"themes": { "themes": {
"type": "array", "type": "array",

View file

@ -1003,8 +1003,8 @@ impl Render for Example {
.bordered(false) .bordered(false)
.p_0() .p_0()
.h_full() .h_full()
.font_family("Monaco") .font_family(cx.theme().mono_font_family.clone())
.text_size(px(12.)) .text_size(cx.theme().mono_font_size)
.focus_bordered(false) .focus_bordered(false)
.into_any_element(), .into_any_element(),
), ),

View file

@ -1,5 +1,6 @@
use gpui::*; use gpui::*;
use gpui_component::{ use gpui_component::{
ActiveTheme as _,
highlighter::Language, highlighter::Language,
input::{Input, InputState, TabSize}, input::{Input, InputState, TabSize},
resizable::h_resizable, resizable::h_resizable,
@ -52,8 +53,8 @@ impl Render for Example {
div() div()
.id("source") .id("source")
.size_full() .size_full()
.font_family("Menlo") .font_family(cx.theme().mono_font_family.clone())
.text_size(px(13.)) .text_size(cx.theme().mono_font_size)
.child( .child(
Input::new(&self.input_state) Input::new(&self.input_state)
.h_full() .h_full()

View file

@ -1,5 +1,6 @@
use gpui::*; use gpui::*;
use gpui_component::{ use gpui_component::{
ActiveTheme as _,
highlighter::Language, highlighter::Language,
input::{Input, InputEvent, InputState, TabSize}, input::{Input, InputEvent, InputState, TabSize},
resizable::{h_resizable, resizable_panel}, resizable::{h_resizable, resizable_panel},
@ -83,8 +84,8 @@ impl Render for Example {
div() div()
.id("source") .id("source")
.size_full() .size_full()
.font_family("Monaco") .font_family(cx.theme().mono_font_family.clone())
.text_size(px(12.)) .text_size(cx.theme().mono_font_size)
.child( .child(
Input::new(&self.input_state) Input::new(&self.input_state)
.h_full() .h_full()

View file

@ -416,7 +416,7 @@ impl Render for StoryTiles {
let notification_layer = Root::render_notification_layer(window, cx); let notification_layer = Root::render_notification_layer(window, cx);
div() div()
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.relative() .relative()
.size_full() .size_full()
.flex() .flex()

View file

@ -8,6 +8,7 @@ use rust_i18n::t;
use crate::{ use crate::{
input::{self, popovers::ContextMenu, InputState}, input::{self, popovers::ContextMenu, InputState},
menu::PopupMenu, menu::PopupMenu,
ActiveTheme as _,
}; };
/// Context menu for mouse right clicks. /// Context menu for mouse right clicks.
@ -125,7 +126,7 @@ impl MouseContextMenu {
} }
impl Render for MouseContextMenu { impl Render for MouseContextMenu {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if !self.open { if !self.open {
return div().into_any_element(); return div().into_any_element();
} }
@ -137,8 +138,7 @@ impl Render for MouseContextMenu {
.position(self.mouse_position) .position(self.mouse_position)
.child( .child(
div() div()
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.text_size(px(14.))
.cursor_default() .cursor_default()
.child(self.menu.clone()), .child(self.menu.clone()),
), ),

View file

@ -414,7 +414,7 @@ impl Render for SearchPanel {
.on_action(cx.listener(Self::on_action_next)) .on_action(cx.listener(Self::on_action_next))
.on_action(cx.listener(Self::on_action_escape)) .on_action(cx.listener(Self::on_action_escape))
.on_action(cx.listener(Self::on_action_tab)) .on_action(cx.listener(Self::on_action_tab))
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.items_center() .items_center()
.py_2() .py_2()
.px_3() .px_3()

View file

@ -434,8 +434,8 @@ impl Render for DivInspector {
v_flex() v_flex()
.flex_1() .flex_1()
.gap_y_1() .gap_y_1()
.font_family("Monaco") .font_family(cx.theme().mono_font_family.clone())
.text_size(px(12.)) .text_size(cx.theme().mono_font_size)
.child(Input::new(&self.rust_state.state).h_full()) .child(Input::new(&self.rust_state.state).h_full())
.when_some(self.rust_state.error.clone(), |this, err| { .when_some(self.rust_state.error.clone(), |this, err| {
this.child(Alert::error("rust-error", err).text_xs()) this.child(Alert::error("rust-error", err).text_xs())
@ -462,8 +462,8 @@ impl Render for DivInspector {
v_flex() v_flex()
.flex_1() .flex_1()
.gap_y_1() .gap_y_1()
.font_family("Monaco") .font_family(cx.theme().mono_font_family.clone())
.text_size(px(12.)) .text_size(cx.theme().mono_font_size)
.child(Input::new(&self.json_state.state).h_full()) .child(Input::new(&self.json_state.state).h_full())
.when_some(self.json_state.error.clone(), |this, err| { .when_some(self.json_state.error.clone(), |this, err| {
this.child(Alert::error("json-error", err).text_xs()) this.child(Alert::error("json-error", err).text_xs())
@ -487,7 +487,7 @@ fn render_inspector(
v_flex() v_flex()
.id("inspector") .id("inspector")
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.size_full() .size_full()
.bg(cx.theme().background) .bg(cx.theme().background)
.border_l_1() .border_l_1()

View file

@ -388,8 +388,7 @@ impl Root {
impl Render for Root { impl Render for Root {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let base_font_size = cx.theme().font_size; window.set_rem_size(cx.theme().font_size);
window.set_rem_size(base_font_size);
window_border().child( window_border().child(
div() div()
@ -399,7 +398,7 @@ impl Render for Root {
.on_action(cx.listener(Self::on_action_tab_prev)) .on_action(cx.listener(Self::on_action_tab_prev))
.relative() .relative()
.size_full() .size_full()
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.bg(cx.theme().background) .bg(cx.theme().background)
.text_color(cx.theme().foreground) .text_color(cx.theme().foreground)
.child(self.view.clone()), .child(self.view.clone()),

View file

@ -371,8 +371,8 @@ impl CodeBlock {
.p_3() .p_3()
.rounded(cx.theme().radius) .rounded(cx.theme().radius)
.bg(cx.theme().secondary.opacity(0.85)) .bg(cx.theme().secondary.opacity(0.85))
.font_family("Menlo, Monaco, Consolas, monospace") .font_family(cx.theme().mono_font_family.clone())
.text_size(rems(0.875)) .text_size(cx.theme().mono_font_size)
.relative() .relative()
.refine_style(&style.code_block) .refine_style(&style.code_block)
.child(Inline::new( .child(Inline::new(

View file

@ -45,8 +45,20 @@ pub struct Theme {
pub dark_theme: Rc<ThemeConfig>, pub dark_theme: Rc<ThemeConfig>,
pub mode: ThemeMode, pub mode: ThemeMode,
/// The font family for the application, default is `.SystemUIFont`.
pub font_family: SharedString, pub font_family: SharedString,
/// The base font size for the application, default is 16px.
pub font_size: Pixels, pub font_size: Pixels,
/// The monospace font family for the application.
///
/// Defaults to:
///
/// - macOS: `Menlo`
/// - Windows: `Consolas`
/// - Linux: `DejaVu Sans Mono`
pub mono_font_family: SharedString,
/// The monospace font size for the application, default is 13px.
pub mono_font_size: Pixels,
/// Radius for the general elements. /// Radius for the general elements.
pub radius: Pixels, pub radius: Pixels,
/// Radius for the large elements, e.g.: Dialog, Notification border radius. /// Radius for the large elements, e.g.: Dialog, Notification border radius.
@ -172,14 +184,17 @@ impl From<&ThemeColor> for Theme {
Theme { Theme {
mode: ThemeMode::default(), mode: ThemeMode::default(),
transparent: Hsla::transparent_black(), transparent: Hsla::transparent_black(),
font_family: ".SystemUIFont".into(),
font_size: px(16.), font_size: px(16.),
font_family: if cfg!(target_os = "macos") { mono_font_family: if cfg!(target_os = "macos") {
".SystemUIFont".into() // https://en.wikipedia.org/wiki/Menlo_(typeface)
"Menlo".into()
} else if cfg!(target_os = "windows") { } else if cfg!(target_os = "windows") {
"Segoe UI".into() "Consolas".into()
} else { } else {
"FreeMono".into() "DejaVu Sans Mono".into()
}, },
mono_font_size: px(13.),
radius: px(6.), radius: px(6.),
radius_lg: px(8.), radius_lg: px(8.),
shadow: true, shadow: true,

View file

@ -41,6 +41,15 @@ pub struct ThemeConfig {
/// The base font family, default is system font: `.SystemUIFont`. /// The base font family, default is system font: `.SystemUIFont`.
#[serde(rename = "font.family")] #[serde(rename = "font.family")]
pub font_family: Option<SharedString>, pub font_family: Option<SharedString>,
/// The monospace font family, default is platform specific:
/// - macOS: `Menlo`
/// - Windows: `Consolas`
/// - Linux: `DejaVu Sans Mono`
#[serde(rename = "mono_font.family")]
pub mono_font_family: Option<SharedString>,
/// The monospace font size, default is 13.
#[serde(rename = "mono_font.size")]
pub mono_font_size: Option<f32>,
/// The border radius for general elements, default is 6. /// The border radius for general elements, default is 6.
#[serde(rename = "radius")] #[serde(rename = "radius")]
@ -652,6 +661,16 @@ impl Theme {
} else { } else {
self.font_family = default_theme.font_family.clone(); self.font_family = default_theme.font_family.clone();
} }
if let Some(mono_font_family) = &config.mono_font_family {
self.mono_font_family = mono_font_family.clone();
} else {
self.mono_font_family = default_theme.mono_font_family.clone();
}
if let Some(mono_font_size) = config.mono_font_size {
self.mono_font_size = px(mono_font_size);
} else {
self.mono_font_size = default_theme.mono_font_size;
}
if let Some(radius) = config.radius { if let Some(radius) = config.radius {
self.radius = px(radius as f32); self.radius = px(radius as f32);
} else { } else {

View file

@ -89,7 +89,7 @@ impl Render for Tooltip {
div().child( div().child(
// Wrap in a child, to ensure the left margin is applied to the tooltip // Wrap in a child, to ensure the left margin is applied to the tooltip
h_flex() h_flex()
.font_family(".SystemUIFont") .font_family(cx.theme().font_family.clone())
.m_3() .m_3()
.bg(cx.theme().popover) .bg(cx.theme().popover)
.text_color(cx.theme().popover_foreground) .text_color(cx.theme().popover_foreground)