1use super::AnyIcon;
2use crate::prelude::*;
3
4#[derive(Default)]
5enum IndicatorKind {
6 #[default]
7 Dot,
8 Bar,
9 Icon(AnyIcon),
10}
11
12#[derive(IntoElement, RegisterComponent)]
13pub struct Indicator {
14 kind: IndicatorKind,
15 border_color: Option<Color>,
16 pub color: Color,
17}
18
19impl Indicator {
20 pub fn dot() -> Self {
21 Self {
22 kind: IndicatorKind::Dot,
23 border_color: None,
24 color: Color::Default,
25 }
26 }
27
28 pub fn bar() -> Self {
29 Self {
30 kind: IndicatorKind::Bar,
31 border_color: None,
32
33 color: Color::Default,
34 }
35 }
36
37 pub fn icon(icon: impl Into<AnyIcon>) -> Self {
38 Self {
39 kind: IndicatorKind::Icon(icon.into()),
40 border_color: None,
41
42 color: Color::Default,
43 }
44 }
45
46 pub fn color(mut self, color: Color) -> Self {
47 self.color = color;
48 self
49 }
50
51 pub fn border_color(mut self, color: Color) -> Self {
52 self.border_color = Some(color);
53 self
54 }
55}
56
57impl RenderOnce for Indicator {
58 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
59 let container = div().flex_none();
60 let container = if let Some(border_color) = self.border_color {
61 if matches!(self.kind, IndicatorKind::Dot | IndicatorKind::Bar) {
62 container.border_1().border_color(border_color.color(cx))
63 } else {
64 container
65 }
66 } else {
67 container
68 };
69
70 match self.kind {
71 IndicatorKind::Icon(icon) => container
72 .child(icon.map(|icon| icon.custom_size(rems_from_px(8.)).color(self.color))),
73 IndicatorKind::Dot => container
74 .w_1p5()
75 .h_1p5()
76 .rounded_full()
77 .bg(self.color.color(cx)),
78 IndicatorKind::Bar => container
79 .w_full()
80 .h_1p5()
81 .rounded_t_sm()
82 .bg(self.color.color(cx)),
83 }
84 }
85}
86
87impl Component for Indicator {
88 fn scope() -> ComponentScope {
89 ComponentScope::Status
90 }
91
92 fn description() -> Option<&'static str> {
93 Some(
94 "Visual indicators used to represent status, notifications, or draw attention to specific elements.",
95 )
96 }
97
98 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
99 Some(
100 v_flex()
101 .gap_6()
102 .children(vec![
103 example_group_with_title(
104 "Dot Indicators",
105 vec![
106 single_example("Default", Indicator::dot().into_any_element()),
107 single_example(
108 "Success",
109 Indicator::dot().color(Color::Success).into_any_element(),
110 ),
111 single_example(
112 "Warning",
113 Indicator::dot().color(Color::Warning).into_any_element(),
114 ),
115 single_example(
116 "Error",
117 Indicator::dot().color(Color::Error).into_any_element(),
118 ),
119 single_example(
120 "With Border",
121 Indicator::dot()
122 .color(Color::Accent)
123 .border_color(Color::Default)
124 .into_any_element(),
125 ),
126 ],
127 ),
128 example_group_with_title(
129 "Bar Indicators",
130 vec![
131 single_example("Default", Indicator::bar().into_any_element()),
132 single_example(
133 "Success",
134 Indicator::bar().color(Color::Success).into_any_element(),
135 ),
136 single_example(
137 "Warning",
138 Indicator::bar().color(Color::Warning).into_any_element(),
139 ),
140 single_example(
141 "Error",
142 Indicator::bar().color(Color::Error).into_any_element(),
143 ),
144 ],
145 ),
146 example_group_with_title(
147 "Icon Indicators",
148 vec![
149 single_example(
150 "Default",
151 Indicator::icon(Icon::new(IconName::Circle)).into_any_element(),
152 ),
153 single_example(
154 "Success",
155 Indicator::icon(Icon::new(IconName::Check))
156 .color(Color::Success)
157 .into_any_element(),
158 ),
159 single_example(
160 "Warning",
161 Indicator::icon(Icon::new(IconName::Warning))
162 .color(Color::Warning)
163 .into_any_element(),
164 ),
165 single_example(
166 "Error",
167 Indicator::icon(Icon::new(IconName::Close))
168 .color(Color::Error)
169 .into_any_element(),
170 ),
171 ],
172 ),
173 ])
174 .into_any_element(),
175 )
176 }
177}