gpui_ui_kit/
badge.rs

1//! Badge component
2//!
3//! Small status indicators and labels.
4
5use gpui::prelude::*;
6use gpui::*;
7
8/// Badge variant
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum BadgeVariant {
11    /// Default gray
12    #[default]
13    Default,
14    /// Primary blue
15    Primary,
16    /// Success green
17    Success,
18    /// Warning yellow
19    Warning,
20    /// Error red
21    Error,
22    /// Info cyan
23    Info,
24}
25
26impl BadgeVariant {
27    fn colors(&self) -> (Rgba, Rgba) {
28        // Returns (background, text_color)
29        match self {
30            BadgeVariant::Default => (rgb(0x3a3a3a), rgb(0xcccccc)),
31            BadgeVariant::Primary => (rgb(0x1a4a7a), rgb(0x7cc4ff)),
32            BadgeVariant::Success => (rgb(0x1a3a1a), rgb(0x7ccc7c)),
33            BadgeVariant::Warning => (rgb(0x3a3a1a), rgb(0xcccc7c)),
34            BadgeVariant::Error => (rgb(0x3a1a1a), rgb(0xcc7c7c)),
35            BadgeVariant::Info => (rgb(0x1a3a3a), rgb(0x7ccccc)),
36        }
37    }
38}
39
40/// Badge size
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
42pub enum BadgeSize {
43    /// Small
44    Sm,
45    /// Medium (default)
46    #[default]
47    Md,
48    /// Large
49    Lg,
50}
51
52/// A badge component
53pub struct Badge {
54    label: SharedString,
55    variant: BadgeVariant,
56    size: BadgeSize,
57    rounded: bool,
58    icon: Option<SharedString>,
59}
60
61impl Badge {
62    /// Create a new badge
63    pub fn new(label: impl Into<SharedString>) -> Self {
64        Self {
65            label: label.into(),
66            variant: BadgeVariant::default(),
67            size: BadgeSize::default(),
68            rounded: false,
69            icon: None,
70        }
71    }
72
73    /// Set variant
74    pub fn variant(mut self, variant: BadgeVariant) -> Self {
75        self.variant = variant;
76        self
77    }
78
79    /// Set size
80    pub fn size(mut self, size: BadgeSize) -> Self {
81        self.size = size;
82        self
83    }
84
85    /// Make fully rounded (pill shape)
86    pub fn rounded(mut self, rounded: bool) -> Self {
87        self.rounded = rounded;
88        self
89    }
90
91    /// Add icon
92    pub fn icon(mut self, icon: impl Into<SharedString>) -> Self {
93        self.icon = Some(icon.into());
94        self
95    }
96
97    /// Build into element
98    pub fn build(self) -> Div {
99        let (bg, text_color) = self.variant.colors();
100
101        let (px_val, py_val) = match self.size {
102            BadgeSize::Sm => (px(6.0), px(2.0)),
103            BadgeSize::Md => (px(8.0), px(3.0)),
104            BadgeSize::Lg => (px(12.0), px(4.0)),
105        };
106
107        let mut badge = div()
108            .flex()
109            .items_center()
110            .gap_1()
111            .px(px_val)
112            .py(py_val)
113            .bg(bg)
114            .text_color(text_color);
115
116        // Apply text size
117        badge = match self.size {
118            BadgeSize::Sm => badge.text_xs(),
119            BadgeSize::Md => badge.text_xs(),
120            BadgeSize::Lg => badge.text_sm(),
121        };
122
123        // Apply rounding
124        if self.rounded {
125            badge = badge.rounded_full();
126        } else {
127            badge = badge.rounded(px(3.0));
128        }
129
130        // Icon
131        if let Some(icon) = self.icon {
132            badge = badge.child(div().child(icon));
133        }
134
135        // Label
136        badge = badge.child(self.label);
137
138        badge
139    }
140}
141
142impl IntoElement for Badge {
143    type Element = Div;
144
145    fn into_element(self) -> Self::Element {
146        self.build()
147    }
148}
149
150/// A dot indicator (no text)
151pub struct BadgeDot {
152    variant: BadgeVariant,
153    size: Pixels,
154}
155
156impl BadgeDot {
157    /// Create a new badge dot
158    pub fn new() -> Self {
159        Self {
160            variant: BadgeVariant::default(),
161            size: px(8.0),
162        }
163    }
164
165    /// Set variant
166    pub fn variant(mut self, variant: BadgeVariant) -> Self {
167        self.variant = variant;
168        self
169    }
170
171    /// Set size in pixels
172    pub fn size(mut self, size: Pixels) -> Self {
173        self.size = size;
174        self
175    }
176
177    /// Build into element
178    pub fn build(self) -> Div {
179        let (bg, _) = self.variant.colors();
180
181        div().w(self.size).h(self.size).rounded_full().bg(bg)
182    }
183}
184
185impl Default for BadgeDot {
186    fn default() -> Self {
187        Self::new()
188    }
189}
190
191impl IntoElement for BadgeDot {
192    type Element = Div;
193
194    fn into_element(self) -> Self::Element {
195        self.build()
196    }
197}