1mod list_header;
2mod list_item;
3mod list_separator;
4mod list_sub_header;
5
6use gpui::{AnyElement, Div};
7use smallvec::SmallVec;
8
9use crate::prelude::*;
10use crate::{v_stack, Label, ToggleState, Toggleable};
11
12pub use list_header::*;
13pub use list_item::*;
14pub use list_separator::*;
15pub use list_sub_header::*;
16
17#[derive(IntoElement)]
18pub struct List {
19 /// Message to display when the list is empty
20 /// Defaults to "No items"
21 empty_message: SharedString,
22 header: Option<ListHeader>,
23 toggle: Toggleable,
24 children: SmallVec<[AnyElement; 2]>,
25}
26
27impl List {
28 pub fn new() -> Self {
29 Self {
30 empty_message: "No items".into(),
31 header: None,
32 toggle: Toggleable::NotToggleable,
33 children: SmallVec::new(),
34 }
35 }
36
37 pub fn empty_message(mut self, empty_message: impl Into<SharedString>) -> Self {
38 self.empty_message = empty_message.into();
39 self
40 }
41
42 pub fn header(mut self, header: ListHeader) -> Self {
43 self.header = Some(header);
44 self
45 }
46
47 pub fn toggle(mut self, toggle: Toggleable) -> Self {
48 self.toggle = toggle;
49 self
50 }
51}
52
53impl ParentElement for List {
54 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
55 &mut self.children
56 }
57}
58
59impl RenderOnce for List {
60 type Rendered = Div;
61
62 fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
63 v_stack()
64 .w_full()
65 .py_1()
66 .children(self.header.map(|header| header))
67 .map(|this| match (self.children.is_empty(), self.toggle) {
68 (false, _) => this.children(self.children),
69 (true, Toggleable::Toggleable(ToggleState::NotToggled)) => this,
70 (true, _) => this.child(Label::new(self.empty_message.clone()).color(Color::Muted)),
71 })
72 }
73}