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 breadcrumb(&self) -> Div {
91 div()
92 .self_start()
93 .flex()
94 .flex_row()
95 .items_center()
96 .gap(px(4.0))
97 .min_w_0()
98 }
99
100 fn breadcrumb_item(&self, label: impl Into<SharedString>, current: bool) -> Div {
102 let theme = self.theme();
103 let mut crumb = div()
104 .min_w_0()
105 .truncate()
106 .text_style(TextStyle::Callout)
107 .child(label.into());
108 crumb = if current {
109 crumb.text_color(theme.text)
110 } else {
111 crumb.text_color(theme.text_muted).cursor_pointer()
112 };
113 crumb
114 }
115
116 fn breadcrumb_separator(&self) -> Svg {
118 let theme = self.theme();
119 crate::icons::icon(crate::icons::glyph::ChevronRight)
120 .size(px(12.0))
121 .text_color(theme.text_faint)
122 }
123
124 fn empty_state(
126 &self,
127 icon: impl Into<Icon>,
128 title: impl Into<SharedString>,
129 hint: impl Into<SharedString>,
130 ) -> Div {
131 let theme = self.theme();
132 div()
133 .w_full()
134 .flex()
135 .flex_col()
136 .items_center()
137 .justify_center()
138 .gap(px(6.0))
139 .py(px(40.0))
140 .child(
141 crate::icons::icon(icon)
142 .size(px(24.0))
143 .text_color(theme.text_faint),
144 )
145 .child(
146 div()
147 .text_style(TextStyle::Headline)
148 .text_color(theme.text)
149 .child(title.into()),
150 )
151 .child(
152 div()
153 .text_style(TextStyle::Callout)
154 .text_color(theme.text_muted)
155 .child(hint.into()),
156 )
157 }
158}
159
160impl Content for Theme {}