list.rs

 1use gpui::AnyElement;
 2use smallvec::SmallVec;
 3
 4use crate::{Label, ListHeader, prelude::*, v_flex};
 5
 6pub enum EmptyMessage {
 7    Text(SharedString),
 8    Element(AnyElement),
 9}
10
11#[derive(IntoElement)]
12pub struct List {
13    /// Message to display when the list is empty
14    /// Defaults to "No items"
15    empty_message: EmptyMessage,
16    header: Option<ListHeader>,
17    toggle: Option<bool>,
18    children: SmallVec<[AnyElement; 2]>,
19}
20
21impl Default for List {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl List {
28    pub fn new() -> Self {
29        Self {
30            empty_message: EmptyMessage::Text("No items".into()),
31            header: None,
32            toggle: None,
33            children: SmallVec::new(),
34        }
35    }
36
37    pub fn empty_message(mut self, message: impl Into<EmptyMessage>) -> Self {
38        self.empty_message = message.into();
39        self
40    }
41
42    pub fn header(mut self, header: impl Into<Option<ListHeader>>) -> Self {
43        self.header = header.into();
44        self
45    }
46
47    pub fn toggle(mut self, toggle: impl Into<Option<bool>>) -> Self {
48        self.toggle = toggle.into();
49        self
50    }
51}
52
53impl ParentElement for List {
54    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
55        self.children.extend(elements)
56    }
57}
58
59impl From<String> for EmptyMessage {
60    fn from(s: String) -> Self {
61        EmptyMessage::Text(SharedString::from(s))
62    }
63}
64
65impl From<&str> for EmptyMessage {
66    fn from(s: &str) -> Self {
67        EmptyMessage::Text(SharedString::from(s.to_owned()))
68    }
69}
70
71impl From<AnyElement> for EmptyMessage {
72    fn from(e: AnyElement) -> Self {
73        EmptyMessage::Element(e)
74    }
75}
76
77impl RenderOnce for List {
78    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
79        v_flex()
80            .w_full()
81            .py(DynamicSpacing::Base04.rems(cx))
82            .children(self.header)
83            .map(|this| match (self.children.is_empty(), self.toggle) {
84                (false, _) => this.children(self.children),
85                (true, Some(false)) => this,
86                (true, _) => match self.empty_message {
87                    EmptyMessage::Text(text) => {
88                        this.px_2().child(Label::new(text).color(Color::Muted))
89                    }
90                    EmptyMessage::Element(element) => this.child(element),
91                },
92            })
93    }
94}