typography.rs

  1use gpui::{
  2    div, rems, IntoElement, ParentElement, Rems, RenderOnce, SharedString, Styled, WindowContext,
  3};
  4use settings::Settings;
  5use theme::{ActiveTheme, ThemeSettings};
  6
  7use crate::{rems_from_px, Color};
  8
  9/// Extends [`gpui::Styled`] with typography-related styling methods.
 10pub trait StyledTypography: Styled + Sized {
 11    /// Sets the font family to the buffer font.
 12    fn font_buffer(self, cx: &WindowContext) -> Self {
 13        let settings = ThemeSettings::get_global(cx);
 14        let buffer_font_family = settings.buffer_font.family.clone();
 15
 16        self.font_family(buffer_font_family)
 17    }
 18
 19    /// Sets the font family to the UI font.
 20    fn font_ui(self, cx: &WindowContext) -> Self {
 21        let settings = ThemeSettings::get_global(cx);
 22        let ui_font_family = settings.ui_font.family.clone();
 23
 24        self.font_family(ui_font_family)
 25    }
 26
 27    /// Sets the text size using a [`UiTextSize`].
 28    fn text_ui_size(self, size: TextSize, cx: &WindowContext) -> Self {
 29        self.text_size(size.rems(cx))
 30    }
 31
 32    /// The large size for UI text.
 33    ///
 34    /// `1rem` or `16px` at the default scale of `1rem` = `16px`.
 35    ///
 36    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
 37    ///
 38    /// Use `text_ui` for regular-sized text.
 39    fn text_ui_lg(self, cx: &WindowContext) -> Self {
 40        self.text_size(TextSize::Large.rems(cx))
 41    }
 42
 43    /// The default size for UI text.
 44    ///
 45    /// `0.825rem` or `14px` at the default scale of `1rem` = `16px`.
 46    ///
 47    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
 48    ///
 49    /// Use `text_ui_sm` for smaller text.
 50    fn text_ui(self, cx: &WindowContext) -> Self {
 51        self.text_size(TextSize::default().rems(cx))
 52    }
 53
 54    /// The small size for UI text.
 55    ///
 56    /// `0.75rem` or `12px` at the default scale of `1rem` = `16px`.
 57    ///
 58    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
 59    ///
 60    /// Use `text_ui` for regular-sized text.
 61    fn text_ui_sm(self, cx: &WindowContext) -> Self {
 62        self.text_size(TextSize::Small.rems(cx))
 63    }
 64
 65    /// The extra small size for UI text.
 66    ///
 67    /// `0.625rem` or `10px` at the default scale of `1rem` = `16px`.
 68    ///
 69    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
 70    ///
 71    /// Use `text_ui` for regular-sized text.
 72    fn text_ui_xs(self, cx: &WindowContext) -> Self {
 73        self.text_size(TextSize::XSmall.rems(cx))
 74    }
 75
 76    /// The font size for buffer text.
 77    ///
 78    /// Retrieves the default font size, or the user's custom font size if set.
 79    ///
 80    /// This should only be used for text that is displayed in a buffer,
 81    /// or other places that text needs to match the user's buffer font size.
 82    fn text_buffer(self, cx: &mut WindowContext) -> Self {
 83        let settings = ThemeSettings::get_global(cx);
 84        self.text_size(settings.buffer_font_size(cx))
 85    }
 86}
 87
 88impl<E: Styled> StyledTypography for E {}
 89
 90#[derive(Debug, Default, Clone)]
 91pub enum TextSize {
 92    /// The default size for UI text.
 93    ///
 94    /// `0.825rem` or `14px` at the default scale of `1rem` = `16px`.
 95    ///
 96    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
 97    #[default]
 98    Default,
 99    /// The large size for UI text.
100    ///
101    /// `1rem` or `16px` at the default scale of `1rem` = `16px`.
102    ///
103    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
104    Large,
105
106    /// The small size for UI text.
107    ///
108    /// `0.75rem` or `12px` at the default scale of `1rem` = `16px`.
109    ///
110    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
111    Small,
112
113    /// The extra small size for UI text.
114    ///
115    /// `0.625rem` or `10px` at the default scale of `1rem` = `16px`.
116    ///
117    /// Note: The absolute size of this text will change based on a user's `ui_scale` setting.
118    XSmall,
119
120    /// The `ui_font_size` set by the user.
121    Ui,
122    /// The `buffer_font_size` set by the user.
123    Editor,
124    // TODO: The terminal settings will need to be passed to
125    // ThemeSettings before we can enable this.
126    //// The `terminal.font_size` set by the user.
127    // Terminal,
128}
129
130impl TextSize {
131    pub fn rems(self, cx: &WindowContext) -> Rems {
132        let theme_settings = ThemeSettings::get_global(cx);
133
134        match self {
135            Self::Large => rems_from_px(16.),
136            Self::Default => rems_from_px(14.),
137            Self::Small => rems_from_px(12.),
138            Self::XSmall => rems_from_px(10.),
139            Self::Ui => rems_from_px(theme_settings.ui_font_size.into()),
140            Self::Editor => rems_from_px(theme_settings.buffer_font_size.into()),
141        }
142    }
143}
144
145/// The size of a [`Headline`] element
146#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
147pub enum HeadlineSize {
148    XSmall,
149    Small,
150    #[default]
151    Medium,
152    Large,
153    XLarge,
154}
155
156impl HeadlineSize {
157    pub fn size(self) -> Rems {
158        match self {
159            // Based on the Major Second scale
160            Self::XSmall => rems(0.88),
161            Self::Small => rems(1.0),
162            Self::Medium => rems(1.125),
163            Self::Large => rems(1.27),
164            Self::XLarge => rems(1.43),
165        }
166    }
167
168    pub fn line_height(self) -> Rems {
169        match self {
170            Self::XSmall => rems(1.6),
171            Self::Small => rems(1.6),
172            Self::Medium => rems(1.6),
173            Self::Large => rems(1.6),
174            Self::XLarge => rems(1.6),
175        }
176    }
177}
178
179#[derive(IntoElement)]
180pub struct Headline {
181    size: HeadlineSize,
182    text: SharedString,
183    color: Color,
184}
185
186impl RenderOnce for Headline {
187    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
188        let ui_font = ThemeSettings::get_global(cx).ui_font.clone();
189
190        div()
191            .font(ui_font)
192            .line_height(self.size.line_height())
193            .text_size(self.size.size())
194            .text_color(cx.theme().colors().text)
195            .child(self.text)
196    }
197}
198
199impl Headline {
200    pub fn new(text: impl Into<SharedString>) -> Self {
201        Self {
202            size: HeadlineSize::default(),
203            text: text.into(),
204            color: Color::default(),
205        }
206    }
207
208    pub fn size(mut self, size: HeadlineSize) -> Self {
209        self.size = size;
210        self
211    }
212
213    pub fn color(mut self, color: Color) -> Self {
214        self.color = color;
215        self
216    }
217}