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