list_sub_header.rs

  1use crate::prelude::*;
  2use component::{Component, ComponentScope, example_group_with_title, single_example};
  3
  4#[derive(IntoElement, RegisterComponent)]
  5pub struct ListSubHeader {
  6    label: SharedString,
  7    start_slot: Option<IconName>,
  8    end_slot: Option<AnyElement>,
  9    inset: bool,
 10    selected: bool,
 11}
 12
 13impl ListSubHeader {
 14    pub fn new(label: impl Into<SharedString>) -> Self {
 15        Self {
 16            label: label.into(),
 17            start_slot: None,
 18            end_slot: None,
 19            inset: false,
 20            selected: false,
 21        }
 22    }
 23
 24    pub fn left_icon(mut self, left_icon: Option<IconName>) -> Self {
 25        self.start_slot = left_icon;
 26        self
 27    }
 28
 29    pub fn end_slot(mut self, end_slot: AnyElement) -> Self {
 30        self.end_slot = Some(end_slot);
 31        self
 32    }
 33
 34    pub fn inset(mut self, inset: bool) -> Self {
 35        self.inset = inset;
 36        self
 37    }
 38}
 39
 40impl Toggleable for ListSubHeader {
 41    fn toggle_state(mut self, selected: bool) -> Self {
 42        self.selected = selected;
 43        self
 44    }
 45}
 46
 47impl RenderOnce for ListSubHeader {
 48    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
 49        h_flex()
 50            .flex_1()
 51            .w_full()
 52            .relative()
 53            .pb(DynamicSpacing::Base04.rems(cx))
 54            .px(DynamicSpacing::Base02.rems(cx))
 55            .child(
 56                div()
 57                    .h_5()
 58                    .when(self.inset, |this| this.px_2())
 59                    .when(self.selected, |this| {
 60                        this.bg(cx.theme().colors().ghost_element_selected)
 61                    })
 62                    .flex()
 63                    .flex_1()
 64                    .w_full()
 65                    .gap_1()
 66                    .items_center()
 67                    .justify_between()
 68                    .child(
 69                        div()
 70                            .flex()
 71                            .gap_1()
 72                            .items_center()
 73                            .children(
 74                                self.start_slot.map(|i| {
 75                                    Icon::new(i).color(Color::Muted).size(IconSize::Small)
 76                                }),
 77                            )
 78                            .child(
 79                                Label::new(self.label.clone())
 80                                    .color(Color::Muted)
 81                                    .size(LabelSize::Small),
 82                            ),
 83                    )
 84                    .children(self.end_slot),
 85            )
 86    }
 87}
 88
 89impl Component for ListSubHeader {
 90    fn scope() -> ComponentScope {
 91        ComponentScope::DataDisplay
 92    }
 93
 94    fn description() -> Option<&'static str> {
 95        Some(
 96            "A sub-header component for organizing list content into subsections with optional icons and end slots.",
 97        )
 98    }
 99
100    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
101        Some(
102            v_flex()
103                .gap_6()
104                .children(vec![
105                    example_group_with_title(
106                        "Basic Sub-headers",
107                        vec![
108                            single_example(
109                                "Simple",
110                                ListSubHeader::new("Subsection").into_any_element(),
111                            ),
112                            single_example(
113                                "With Icon",
114                                ListSubHeader::new("Documents")
115                                    .left_icon(Some(IconName::File))
116                                    .into_any_element(),
117                            ),
118                            single_example(
119                                "With End Slot",
120                                ListSubHeader::new("Recent")
121                                    .end_slot(
122                                        Label::new("3").color(Color::Muted).into_any_element(),
123                                    )
124                                    .into_any_element(),
125                            ),
126                        ],
127                    ),
128                    example_group_with_title(
129                        "States",
130                        vec![
131                            single_example(
132                                "Selected",
133                                ListSubHeader::new("Selected")
134                                    .toggle_state(true)
135                                    .into_any_element(),
136                            ),
137                            single_example(
138                                "Inset",
139                                ListSubHeader::new("Inset Sub-header")
140                                    .inset(true)
141                                    .into_any_element(),
142                            ),
143                        ],
144                    ),
145                ])
146                .into_any_element(),
147        )
148    }
149}