Skip to main content

ui/components/
description_list.rs

1use gpui::AnyElement;
2
3use crate::prelude::*;
4
5/// Layout mode of a [`DescriptionList`] row.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum DescriptionListMode {
8    /// Label above value (mobile-style).
9    #[default]
10    Stacked,
11    /// Label left, value right.
12    Horizontal,
13}
14
15/// A key-value list for displaying structured details (Tailwind "Description List").
16#[derive(IntoElement, RegisterComponent)]
17pub struct DescriptionList {
18    mode: DescriptionListMode,
19    items: Vec<(SharedString, AnyElement)>,
20}
21
22impl DescriptionList {
23    pub fn new() -> Self {
24        Self {
25            mode: DescriptionListMode::default(),
26            items: Vec::new(),
27        }
28    }
29
30    pub fn mode(mut self, mode: DescriptionListMode) -> Self {
31        self.mode = mode;
32        self
33    }
34
35    pub fn item(mut self, label: impl Into<SharedString>, value: impl IntoElement) -> Self {
36        self.items.push((label.into(), value.into_any_element()));
37        self
38    }
39}
40
41impl Default for DescriptionList {
42    fn default() -> Self {
43        Self::new()
44    }
45}
46
47impl RenderOnce for DescriptionList {
48    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
49        let mode = self.mode;
50
51        v_flex()
52            .w_full()
53            .children(
54                self.items
55                    .into_iter()
56                    .enumerate()
57                    .map(move |(index, (label, value))| {
58                        let label = Label::new(label).size(LabelSize::Small).color(Color::Muted);
59
60                        let row = match mode {
61                            DescriptionListMode::Stacked => v_flex()
62                                .gap_1()
63                                .child(label)
64                                .child(value)
65                                .into_any_element(),
66                            DescriptionListMode::Horizontal => h_flex()
67                                .justify_between()
68                                .gap_4()
69                                .child(label)
70                                .child(div().child(value))
71                                .into_any_element(),
72                        };
73
74                        div()
75                            .w_full()
76                            .py_4()
77                            .when(index > 0, |this| {
78                                this.border_t_1().border_color(semantic::border_muted(cx))
79                            })
80                            .child(row)
81                    }),
82            )
83    }
84}
85
86impl Component for DescriptionList {
87    fn scope() -> ComponentScope {
88        ComponentScope::DataDisplay
89    }
90
91    fn description() -> Option<&'static str> {
92        Some("A key-value list for displaying structured details, in stacked or horizontal mode.")
93    }
94
95    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
96        Some(
97            v_flex()
98                .gap_6()
99                .children(vec![
100                    example_group_with_title(
101                        "Stacked",
102                        vec![single_example(
103                            "Stacked mode",
104                            DescriptionList::new()
105                                .item("Full name", Label::new("Margot Foster"))
106                                .item("Application for", Label::new("Backend Developer"))
107                                .item("Email address", Label::new("margotfoster@example.com"))
108                                .into_any_element(),
109                        )],
110                    ),
111                    example_group_with_title(
112                        "Horizontal",
113                        vec![single_example(
114                            "Horizontal mode",
115                            DescriptionList::new()
116                                .mode(DescriptionListMode::Horizontal)
117                                .item("Full name", Label::new("Margot Foster"))
118                                .item("Application for", Label::new("Backend Developer"))
119                                .item("Email address", Label::new("margotfoster@example.com"))
120                                .into_any_element(),
121                        )],
122                    ),
123                ])
124                .into_any_element(),
125        )
126    }
127}