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