Skip to main content

guise/
indicator.rs

1//! `Indicator` — a dot or count badge overlaid on a child element.
2
3use gpui::prelude::*;
4use gpui::{div, px, AnyElement, App, FontWeight, IntoElement, SharedString, Window};
5
6use crate::devtools::Probed;
7use crate::theme::{theme, ColorName};
8
9/// A corner indicator over any child.
10#[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    /// Show a count/text instead of a plain dot.
29    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    /// Hide the indicator (but keep the child).
40    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}