use gpui::AnyElement; use smallvec::SmallVec; use crate::{prelude::*, v_flex, Label, ListHeader}; pub enum EmptyMessage { Text(SharedString), Element(AnyElement), } #[derive(IntoElement)] pub struct List { /// Message to display when the list is empty /// Defaults to "No items" empty_message: EmptyMessage, header: Option, toggle: Option, children: SmallVec<[AnyElement; 2]>, } impl Default for List { fn default() -> Self { Self::new() } } impl List { pub fn new() -> Self { Self { empty_message: EmptyMessage::Text("No items".into()), header: None, toggle: None, children: SmallVec::new(), } } pub fn empty_message(mut self, message: impl Into) -> Self { self.empty_message = message.into(); self } pub fn header(mut self, header: impl Into>) -> Self { self.header = header.into(); self } pub fn toggle(mut self, toggle: impl Into>) -> Self { self.toggle = toggle.into(); self } } impl ParentElement for List { fn extend(&mut self, elements: impl IntoIterator) { self.children.extend(elements) } } impl From for EmptyMessage { fn from(s: String) -> Self { EmptyMessage::Text(SharedString::from(s)) } } impl From<&str> for EmptyMessage { fn from(s: &str) -> Self { EmptyMessage::Text(SharedString::from(s.to_owned())) } } impl From for EmptyMessage { fn from(e: AnyElement) -> Self { EmptyMessage::Element(e) } } impl RenderOnce for List { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { v_flex() .w_full() .py(DynamicSpacing::Base04.rems(cx)) .children(self.header) .map(|this| match (self.children.is_empty(), self.toggle) { (false, _) => this.children(self.children), (true, Some(false)) => this, (true, _) => match self.empty_message { EmptyMessage::Text(text) => this.child(Label::new(text).color(Color::Muted)), EmptyMessage::Element(element) => this.child(element), }, }) } }