1use std::rc::Rc;
 2
 3use crate::Divider;
 4use crate::DividerColor;
 5use crate::Tooltip;
 6use crate::component_prelude::*;
 7use crate::prelude::*;
 8use gpui::AnyView;
 9use gpui::{AnyElement, IntoElement, SharedString, Window};
10
11#[derive(IntoElement, RegisterComponent)]
12pub struct Badge {
13    label: SharedString,
14    icon: IconName,
15    tooltip: Option<Rc<dyn Fn(&mut Window, &mut App) -> AnyView>>,
16}
17
18impl Badge {
19    pub fn new(label: impl Into<SharedString>) -> Self {
20        Self {
21            label: label.into(),
22            icon: IconName::Check,
23            tooltip: None,
24        }
25    }
26
27    pub fn icon(mut self, icon: IconName) -> Self {
28        self.icon = icon;
29        self
30    }
31
32    pub fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
33        self.tooltip = Some(Rc::new(tooltip));
34        self
35    }
36}
37
38impl RenderOnce for Badge {
39    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
40        let tooltip = self.tooltip;
41
42        h_flex()
43            .id(self.label.clone())
44            .h_full()
45            .gap_1()
46            .pl_1()
47            .pr_2()
48            .border_1()
49            .border_color(cx.theme().colors().border.opacity(0.6))
50            .bg(cx.theme().colors().element_background)
51            .rounded_sm()
52            .overflow_hidden()
53            .child(
54                Icon::new(self.icon)
55                    .size(IconSize::XSmall)
56                    .color(Color::Muted),
57            )
58            .child(Divider::vertical().color(DividerColor::Border))
59            .child(Label::new(self.label.clone()).size(LabelSize::Small).ml_1())
60            .when_some(tooltip, |this, tooltip| {
61                this.hoverable_tooltip(move |window, cx| tooltip(window, cx))
62            })
63    }
64}
65
66impl Component for Badge {
67    fn scope() -> ComponentScope {
68        ComponentScope::DataDisplay
69    }
70
71    fn description() -> Option<&'static str> {
72        Some(
73            "A compact, labeled component with optional icon for displaying status, categories, or metadata.",
74        )
75    }
76
77    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
78        Some(
79            v_flex()
80                .gap_6()
81                .child(single_example(
82                    "Basic Badge",
83                    Badge::new("Default").into_any_element(),
84                ))
85                .child(single_example(
86                    "With Tooltip",
87                    Badge::new("Tooltip")
88                        .tooltip(Tooltip::text("This is a tooltip."))
89                        .into_any_element(),
90                ))
91                .into_any_element(),
92        )
93    }
94}