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 {
46 let theme = self.theme();
47 div()
48 .flex_none()
49 .size(px(28.0))
50 .rounded_full()
51 .bg(theme.ink(0.12))
52 .flex()
53 .items_center()
54 .justify_center()
55 .text_style(TextStyle::Subheadline)
56 .font_weight(gpui::FontWeight::MEDIUM)
57 .text_color(theme.text_muted)
58 .child(initials.into())
59 }
60
61 fn tag(&self, label: impl Into<SharedString>) -> Div {
64 let theme = self.theme();
65 div()
66 .self_start()
67 .flex()
68 .flex_row()
69 .items_center()
70 .gap(px(5.0))
71 .pl(px(8.0))
72 .pr(px(5.0))
73 .py(px(3.0))
74 .rounded(px(Theme::control_radius()))
75 .bg(theme.ink(0.07))
76 .border_1()
77 .border_color(theme.border)
78 .text_style(TextStyle::Callout)
79 .text_color(theme.text)
80 .child(label.into())
81 .child(
82 crate::icons::icon(crate::icons::glyph::X)
83 .size(px(10.0))
84 .text_color(theme.text_faint),
85 )
86 }
87
88 fn chip(&self, label: impl Into<SharedString>, tint: gpui::Hsla) -> Div {
93 let theme = self.theme();
94 div()
95 .flex_none()
96 .flex()
97 .flex_row()
98 .items_center()
99 .gap(px(2.0))
100 .px(px(6.0))
101 .rounded(px(Theme::control_radius()))
102 .bg(tint.opacity(0.22))
103 .text_style(TextStyle::Callout)
104 .text_color(theme.text)
105 .child(div().min_w_0().truncate().child(label.into()))
106 }
107
108 fn breadcrumb(&self) -> Div {
111 div()
112 .self_start()
113 .flex()
114 .flex_row()
115 .items_center()
116 .gap(px(4.0))
117 .min_w_0()
118 }
119
120 fn breadcrumb_item(&self, label: impl Into<SharedString>, current: bool) -> Div {
122 let theme = self.theme();
123 let mut crumb = div()
124 .min_w_0()
125 .truncate()
126 .text_style(TextStyle::Callout)
127 .child(label.into());
128 crumb = if current {
129 crumb.text_color(theme.text)
130 } else {
131 crumb.text_color(theme.text_muted).cursor_pointer()
132 };
133 crumb
134 }
135
136 fn breadcrumb_separator(&self) -> Svg {
138 let theme = self.theme();
139 crate::icons::icon(crate::icons::glyph::ChevronRight)
140 .size(px(12.0))
141 .text_color(theme.text_faint)
142 }
143
144 fn empty_state(
146 &self,
147 icon: impl Into<Icon>,
148 title: impl Into<SharedString>,
149 hint: impl Into<SharedString>,
150 ) -> Div {
151 let theme = self.theme();
152 div()
153 .w_full()
154 .flex()
155 .flex_col()
156 .items_center()
157 .justify_center()
158 .gap(px(6.0))
159 .py(px(40.0))
160 .child(
161 crate::icons::icon(icon)
162 .size(px(24.0))
163 .text_color(theme.text_faint),
164 )
165 .child(
166 div()
167 .text_style(TextStyle::Headline)
168 .text_color(theme.text)
169 .child(title.into()),
170 )
171 .child(
172 div()
173 .text_style(TextStyle::Callout)
174 .text_color(theme.text_muted)
175 .child(hint.into()),
176 )
177 }
178}
179
180impl Content for Theme {}