Skip to main content

liora_components/
label.rs

1use gpui::{
2    AnyElement, App, Component, Hsla, IntoElement, Pixels, RenderOnce, SharedString, Window, div,
3    prelude::*, px,
4};
5use liora_core::Config;
6use liora_icons::Icon;
7use liora_icons_lucide::IconName;
8
9pub struct Label {
10    text: SharedString,
11    icon: Option<IconName>,
12    custom_icon: Option<AnyElement>,
13    gap: Pixels,
14    color: Option<Hsla>,
15    size: Pixels,
16}
17
18impl Label {
19    pub fn new(text: impl Into<SharedString>) -> Self {
20        Self {
21            text: text.into(),
22            icon: None,
23            custom_icon: None,
24            gap: px(6.0),
25            color: None,
26            size: px(13.0),
27        }
28    }
29
30    pub fn icon(mut self, icon: IconName) -> Self {
31        self.icon = Some(icon);
32        self
33    }
34    pub fn custom_icon(mut self, icon: impl IntoElement) -> Self {
35        self.custom_icon = Some(icon.into_any_element());
36        self
37    }
38    pub fn gap(mut self, gap: impl Into<Pixels>) -> Self {
39        self.gap = gap.into().max(px(0.0));
40        self
41    }
42    pub fn color(mut self, color: Hsla) -> Self {
43        self.color = Some(color);
44        self
45    }
46    pub fn size(mut self, size: impl Into<Pixels>) -> Self {
47        self.size = size.into().max(px(8.0));
48        self
49    }
50}
51
52impl RenderOnce for Label {
53    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
54        let theme = cx.global::<Config>().theme.clone();
55        let color = self.color.unwrap_or(theme.neutral.text_2);
56        let has_custom_icon = self.custom_icon.is_some();
57        div()
58            .flex()
59            .items_center()
60            .gap(self.gap)
61            .text_size(self.size)
62            .text_color(color)
63            .when_some(self.custom_icon, |s, icon| s.child(icon))
64            .when(!has_custom_icon, |s| {
65                if let Some(icon) = self.icon {
66                    s.child(Icon::new(icon).size(self.size).color(color))
67                } else {
68                    s
69                }
70            })
71            .child(self.text)
72    }
73}
74
75impl IntoElement for Label {
76    type Element = Component<Self>;
77    fn into_element(self) -> Self::Element {
78        Component::new(self)
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    #[test]
86    fn label_builders_track_state() {
87        let label = Label::new("CPU")
88            .icon(IconName::Activity)
89            .gap(px(10.0))
90            .size(px(15.0));
91        assert_eq!(label.gap, px(10.0));
92        assert_eq!(label.size, px(15.0));
93        assert_eq!(label.icon, Some(IconName::Activity));
94    }
95}