liora_components/
label.rs1use 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}