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}