Skip to main content

rgpui_component/sidebar/
group.rs

1use crate::{ActiveTheme, Collapsible, h_flex, sidebar::SidebarItem, v_flex};
2use rgpui::{
3    App, ElementId, IntoElement, ParentElement, SharedString, Styled as _, Window, div,
4    prelude::FluentBuilder as _,
5};
6
7/// A group of items in the [`super::Sidebar`].
8#[derive(Clone)]
9pub struct SidebarGroup<E: SidebarItem + 'static> {
10    label: SharedString,
11    collapsed: bool,
12    children: Vec<E>,
13}
14
15impl<E: SidebarItem> SidebarGroup<E> {
16    /// Create a new [`SidebarGroup`] with the given label.
17    pub fn new(label: impl Into<SharedString>) -> Self {
18        Self {
19            label: label.into(),
20            collapsed: false,
21            children: Vec::new(),
22        }
23    }
24
25    /// Add a child to the sidebar group, the child should implement [`SidebarItem`].
26    pub fn child(mut self, child: E) -> Self {
27        self.children.push(child);
28        self
29    }
30
31    /// Add multiple children to the sidebar group.
32    ///
33    /// See also [`SidebarGroup::child`].
34    pub fn children(mut self, children: impl IntoIterator<Item = E>) -> Self {
35        self.children.extend(children);
36        self
37    }
38}
39
40impl<E: SidebarItem> Collapsible for SidebarGroup<E> {
41    fn is_collapsed(&self) -> bool {
42        self.collapsed
43    }
44
45    fn collapsed(mut self, collapsed: bool) -> Self {
46        self.collapsed = collapsed;
47        self
48    }
49}
50
51impl<E: SidebarItem> SidebarItem for SidebarGroup<E> {
52    fn render(
53        self,
54        id: impl Into<ElementId>,
55        window: &mut Window,
56        cx: &mut App,
57    ) -> impl IntoElement {
58        let id = id.into();
59
60        v_flex()
61            .relative()
62            .when(!self.collapsed, |this| {
63                this.child(
64                    h_flex()
65                        .flex_shrink_0()
66                        .px_2()
67                        .rounded(cx.theme().radius)
68                        .text_xs()
69                        .text_color(cx.theme().sidebar_foreground.opacity(0.7))
70                        .h_8()
71                        .child(self.label),
72                )
73            })
74            .child(
75                div()
76                    .gap_2()
77                    .flex_col()
78                    .children(self.children.into_iter().enumerate().map(|(ix, child)| {
79                        child
80                            .collapsed(self.collapsed)
81                            .render(format!("{}-{}", id, ix), window, cx)
82                            .into_any_element()
83                    })),
84            )
85    }
86}