Skip to repository content140 lines · 4.2 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T05:52:27.753Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
list.rs
1use component::{Component, ComponentScope, example_group_with_title, single_example};
2use gpui::AnyElement;
3use smallvec::SmallVec;
4
5use crate::{Label, ListHeader, ListItem, prelude::*};
6
7pub enum EmptyMessage {
8 Text(SharedString),
9 Element(AnyElement),
10}
11
12#[derive(IntoElement, RegisterComponent)]
13pub struct List {
14 /// Message to display when the list is empty
15 /// Defaults to "No items"
16 empty_message: EmptyMessage,
17 header: Option<ListHeader>,
18 toggle: Option<bool>,
19 children: SmallVec<[AnyElement; 2]>,
20}
21
22impl Default for List {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl List {
29 pub fn new() -> Self {
30 Self {
31 empty_message: EmptyMessage::Text("No items".into()),
32 header: None,
33 toggle: None,
34 children: SmallVec::new(),
35 }
36 }
37
38 pub fn empty_message(mut self, message: impl Into<EmptyMessage>) -> Self {
39 self.empty_message = message.into();
40 self
41 }
42
43 pub fn header(mut self, header: impl Into<Option<ListHeader>>) -> Self {
44 self.header = header.into();
45 self
46 }
47
48 pub fn toggle(mut self, toggle: impl Into<Option<bool>>) -> Self {
49 self.toggle = toggle.into();
50 self
51 }
52}
53
54impl ParentElement for List {
55 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
56 self.children.extend(elements)
57 }
58}
59
60impl From<String> for EmptyMessage {
61 fn from(s: String) -> Self {
62 EmptyMessage::Text(SharedString::from(s))
63 }
64}
65
66impl From<&str> for EmptyMessage {
67 fn from(s: &str) -> Self {
68 EmptyMessage::Text(SharedString::from(s.to_owned()))
69 }
70}
71
72impl From<AnyElement> for EmptyMessage {
73 fn from(e: AnyElement) -> Self {
74 EmptyMessage::Element(e)
75 }
76}
77
78impl RenderOnce for List {
79 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
80 v_flex()
81 .w_full()
82 .py(DynamicSpacing::Base04.rems(cx))
83 .children(self.header)
84 .map(|this| match (self.children.is_empty(), self.toggle) {
85 (false, _) => this.children(self.children),
86 (true, Some(false)) => this,
87 (true, _) => match self.empty_message {
88 EmptyMessage::Text(text) => {
89 this.px_2().child(Label::new(text).color(Color::Muted))
90 }
91 EmptyMessage::Element(element) => this.child(element),
92 },
93 })
94 }
95}
96
97impl Component for List {
98 fn scope() -> ComponentScope {
99 ComponentScope::Layout
100 }
101
102 fn description() -> &'static str {
103 "A container component for displaying a collection of list items \
104 with optional header and empty state."
105 }
106
107 fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
108 v_flex()
109 .gap_6()
110 .children(vec![example_group_with_title(
111 "Basic Lists",
112 vec![
113 single_example(
114 "Simple List",
115 List::new()
116 .child(ListItem::new("item1").child(Label::new("Item 1")))
117 .child(ListItem::new("item2").child(Label::new("Item 2")))
118 .child(ListItem::new("item3").child(Label::new("Item 3")))
119 .into_any_element(),
120 ),
121 single_example(
122 "With Header",
123 List::new()
124 .header(ListHeader::new("Section Header"))
125 .child(ListItem::new("item1").child(Label::new("Item 1")))
126 .child(ListItem::new("item2").child(Label::new("Item 2")))
127 .into_any_element(),
128 ),
129 single_example(
130 "Empty List",
131 List::new()
132 .empty_message("No items to display")
133 .into_any_element(),
134 ),
135 ],
136 )])
137 .into_any_element()
138 }
139}
140