1use std::rc::Rc;
2
3use gpui::{AnyElement, ClickEvent, Div};
4use smallvec::SmallVec;
5
6use crate::prelude::*;
7use crate::{h_stack, Disclosure, Icon, IconElement, IconSize, Label};
8
9#[derive(IntoElement)]
10pub struct ListHeader {
11 label: SharedString,
12 left_icon: Option<Icon>,
13 meta: SmallVec<[AnyElement; 2]>,
14 toggle: Option<bool>,
15 on_toggle: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
16 inset: bool,
17 selected: bool,
18}
19
20impl ListHeader {
21 pub fn new(label: impl Into<SharedString>) -> Self {
22 Self {
23 label: label.into(),
24 left_icon: None,
25 meta: SmallVec::new(),
26 inset: false,
27 toggle: None,
28 on_toggle: None,
29 selected: false,
30 }
31 }
32
33 pub fn toggle(mut self, toggle: impl Into<Option<bool>>) -> Self {
34 self.toggle = toggle.into();
35 self
36 }
37
38 pub fn on_toggle(
39 mut self,
40 on_toggle: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
41 ) -> Self {
42 self.on_toggle = Some(Rc::new(on_toggle));
43 self
44 }
45
46 pub fn left_icon(mut self, left_icon: impl Into<Option<Icon>>) -> Self {
47 self.left_icon = left_icon.into();
48 self
49 }
50
51 pub fn meta(mut self, meta: impl IntoElement) -> Self {
52 self.meta.push(meta.into_any_element());
53 self
54 }
55}
56
57impl Selectable for ListHeader {
58 fn selected(mut self, selected: bool) -> Self {
59 self.selected = selected;
60 self
61 }
62}
63
64impl RenderOnce for ListHeader {
65 type Rendered = Div;
66
67 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
68 h_stack().w_full().relative().child(
69 div()
70 .h_5()
71 .when(self.inset, |this| this.px_2())
72 .when(self.selected, |this| {
73 this.bg(cx.theme().colors().ghost_element_selected)
74 })
75 .flex()
76 .flex_1()
77 .items_center()
78 .justify_between()
79 .w_full()
80 .gap_1()
81 .child(
82 h_stack()
83 .gap_1()
84 .child(
85 div()
86 .flex()
87 .gap_1()
88 .items_center()
89 .children(self.left_icon.map(|i| {
90 IconElement::new(i)
91 .color(Color::Muted)
92 .size(IconSize::Small)
93 }))
94 .child(Label::new(self.label.clone()).color(Color::Muted)),
95 )
96 .children(
97 self.toggle
98 .map(|is_open| Disclosure::new(is_open).on_toggle(self.on_toggle)),
99 ),
100 )
101 .child(h_stack().gap_2().items_center().children(self.meta)),
102 )
103 }
104}