1use gpui::{Div, SharedString, Svg, div, prelude::*, px};
7use icons::Icon;
8use theme::{TextStyle, Theme, ThemeExt, Typeset};
9
10pub trait Content: ThemeExt {
11 fn badge(&self, label: impl Into<SharedString>) -> Div {
13 let theme = self.theme();
14 div()
15 .flex_none()
16 .px(px(8.0))
17 .py(px(2.0))
18 .rounded_full()
19 .border_1()
20 .border_color(theme.border)
21 .text_style(TextStyle::Caption)
22 .text_color(theme.text_muted)
23 .child(label.into())
24 }
25
26 fn badge_active(&self, label: impl Into<SharedString>) -> Div {
29 let theme = self.theme();
30 let emerald = theme.success;
31 let emerald_text = theme.success_muted; div()
33 .flex_none()
34 .px(px(8.0))
35 .py(px(2.0))
36 .rounded_full()
37 .bg(emerald.opacity(0.12))
38 .text_style(TextStyle::Caption)
39 .text_color(emerald_text.opacity(0.9))
40 .child(label.into())
41 }
42
43 fn avatar(&self, initials: impl Into<SharedString>) -> Div {
47 let theme = self.theme();
48 div()
49 .flex_none()
50 .size(px(28.0))
51 .rounded_full()
52 .bg(theme.ink(0.12))
53 .flex()
54 .items_center()
55 .justify_center()
56 .text_style(TextStyle::Subheadline)
57 .font_weight(gpui::FontWeight::MEDIUM)
58 .text_color(theme.text_muted)
59 .child(initials.into())
60 }
61
62 fn tag(&self, label: impl Into<SharedString>) -> Div {
65 let theme = self.theme();
66 div()
67 .self_start()
68 .flex()
69 .flex_row()
70 .items_center()
71 .gap(px(5.0))
72 .pl(px(8.0))
73 .pr(px(5.0))
74 .py(px(3.0))
75 .rounded(px(Theme::control_radius()))
76 .bg(theme.ink(0.07))
77 .border_1()
78 .border_color(theme.border)
79 .text_style(TextStyle::Callout)
80 .text_color(theme.text)
81 .child(label.into())
82 .child(
83 crate::icons::icon(crate::icons::glyph::X)
84 .size(px(10.0))
85 .text_color(theme.text_faint),
86 )
87 }
88
89 fn chip(&self, label: impl Into<SharedString>, tint: gpui::Hsla) -> Div {
94 let theme = self.theme();
95 div()
96 .flex_none()
97 .flex()
98 .flex_row()
99 .items_center()
100 .gap(px(2.0))
101 .px(px(6.0))
102 .rounded(px(Theme::control_radius()))
103 .bg(tint.opacity(0.22))
104 .text_style(TextStyle::Callout)
105 .text_color(theme.text)
106 .child(div().min_w_0().truncate().child(label.into()))
107 }
108
109 fn breadcrumb(&self) -> Div {
112 div()
113 .self_start()
114 .flex()
115 .flex_row()
116 .items_center()
117 .gap(px(4.0))
118 .min_w_0()
119 }
120
121 fn breadcrumb_item(&self, label: impl Into<SharedString>, current: bool) -> Div {
123 let theme = self.theme();
124 let mut crumb = div()
125 .min_w_0()
126 .truncate()
127 .text_style(TextStyle::Callout)
128 .child(label.into());
129 crumb = if current {
130 crumb.text_color(theme.text)
131 } else {
132 crumb.text_color(theme.text_muted).cursor_pointer()
133 };
134 crumb
135 }
136
137 fn breadcrumb_separator(&self) -> Svg {
139 let theme = self.theme();
140 crate::icons::icon(crate::icons::glyph::ChevronRight)
141 .size(px(12.0))
142 .text_color(theme.text_faint)
143 }
144
145 fn empty_state(
147 &self,
148 icon: impl Into<Icon>,
149 title: impl Into<SharedString>,
150 hint: impl Into<SharedString>,
151 ) -> Div {
152 let theme = self.theme();
153 div()
154 .w_full()
155 .flex()
156 .flex_col()
157 .items_center()
158 .justify_center()
159 .gap(px(6.0))
160 .py(px(40.0))
161 .child(
162 crate::icons::icon(icon)
163 .size(px(24.0))
164 .text_color(theme.text_faint),
165 )
166 .child(
167 div()
168 .text_style(TextStyle::Headline)
169 .text_color(theme.text)
170 .child(title.into()),
171 )
172 .child(
173 div()
174 .text_style(TextStyle::Callout)
175 .text_color(theme.text_muted)
176 .child(hint.into()),
177 )
178 }
179}
180
181impl Content for Theme {}