1use gpui::prelude::*;
4use gpui::{div, px, AnyElement, App, FontWeight, IntoElement, SharedString, Window};
5
6use crate::theme::{theme, ColorName};
7
8#[derive(IntoElement)]
10pub struct Indicator {
11 child: AnyElement,
12 label: Option<SharedString>,
13 color: ColorName,
14 disabled: bool,
15}
16
17impl Indicator {
18 pub fn new(child: impl IntoElement) -> Self {
19 Indicator {
20 child: child.into_any_element(),
21 label: None,
22 color: ColorName::Red,
23 disabled: false,
24 }
25 }
26
27 pub fn label(mut self, label: impl Into<SharedString>) -> Self {
29 self.label = Some(label.into());
30 self
31 }
32
33 pub fn color(mut self, color: ColorName) -> Self {
34 self.color = color;
35 self
36 }
37
38 pub fn disabled(mut self, disabled: bool) -> Self {
40 self.disabled = disabled;
41 self
42 }
43}
44
45impl RenderOnce for Indicator {
46 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
47 let t = theme(cx);
48 let accent = t.color(self.color, t.primary_shade());
49 let fg = accent.contrasting().hsla();
50 let bg = accent.hsla();
51
52 let mut root = div().relative().child(self.child);
53 if !self.disabled {
54 let dot = match self.label {
55 Some(label) => div()
56 .absolute()
57 .top(px(-4.0))
58 .right(px(-4.0))
59 .h(px(16.0))
60 .min_w(px(16.0))
61 .px(px(4.0))
62 .flex()
63 .items_center()
64 .justify_center()
65 .rounded(px(16.0))
66 .bg(bg)
67 .text_color(fg)
68 .text_size(px(10.0))
69 .font_weight(FontWeight::BOLD)
70 .child(label),
71 None => div()
72 .absolute()
73 .top(px(-2.0))
74 .right(px(-2.0))
75 .w(px(10.0))
76 .h(px(10.0))
77 .rounded(px(10.0))
78 .bg(bg),
79 };
80 root = root.child(dot);
81 }
82 root
83 }
84}