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