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