Skip to main content

gpui_component/sidebar/
group.rs

1use crate::{ActiveTheme, Collapsible, h_flex, v_flex};
2use gpui::{
3    App, Div, IntoElement, ParentElement, RenderOnce, SharedString, Styled as _, Window, div,
4    prelude::FluentBuilder as _,
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            .when(!self.collapsed, |this| {
58                this.child(
59                    h_flex()
60                        .flex_shrink_0()
61                        .px_2()
62                        .rounded(cx.theme().radius)
63                        .text_xs()
64                        .text_color(cx.theme().sidebar_foreground.opacity(0.7))
65                        .h_8()
66                        .child(self.label),
67                )
68            })
69            .child(
70                self.base.children(
71                    self.children
72                        .into_iter()
73                        .map(|child| child.collapsed(self.collapsed)),
74                ),
75            )
76    }
77}