gpui_component/sidebar/
group.rs

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