ragrig_gpui/
side_panel.rs1use gpui_kit::{
4 AnyElement, ElementId, FontWeight, InteractiveElement as _, IntoElement, ParentElement,
5 RenderOnce, SharedString, Styled as _, Window,
6 component::{ActiveTheme as _, h_flex, scroll::ScrollableElement as _, v_flex},
7 div,
8 prelude::FluentBuilder as _,
9 px,
10};
11
12#[derive(IntoElement)]
18pub struct SidePanel {
19 id: SharedString,
20 title: SharedString,
21 subtitle: Option<SharedString>,
22 actions: Vec<AnyElement>,
23 children: Vec<AnyElement>,
24 footer: Option<AnyElement>,
25}
26
27impl SidePanel {
28 pub fn new(id: impl Into<SharedString>, title: impl Into<SharedString>) -> Self {
33 Self {
34 id: id.into(),
35 title: title.into(),
36 subtitle: None,
37 actions: Vec::new(),
38 children: Vec::new(),
39 footer: None,
40 }
41 }
42
43 pub fn subtitle(mut self, subtitle: impl Into<SharedString>) -> Self {
45 self.subtitle = Some(subtitle.into());
46 self
47 }
48
49 pub fn action(mut self, action: impl IntoElement) -> Self {
51 self.actions.push(action.into_any_element());
52 self
53 }
54
55 pub fn footer(mut self, footer: impl IntoElement) -> Self {
57 self.footer = Some(footer.into_any_element());
58 self
59 }
60}
61
62impl ParentElement for SidePanel {
63 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
64 self.children.extend(elements);
65 }
66}
67
68impl RenderOnce for SidePanel {
69 fn render(self, _: &mut Window, cx: &mut gpui_kit::App) -> impl IntoElement {
70 let theme = cx.theme();
71 let body_id = ElementId::Name(format!("{}-body", self.id).into());
72
73 let header = v_flex()
74 .gap_1()
75 .px_3()
76 .py_3()
77 .border_b_1()
78 .border_color(theme.border)
79 .child(
80 h_flex()
81 .justify_between()
82 .gap_2()
83 .child(
84 div()
85 .text_lg()
86 .font_weight(FontWeight::SEMIBOLD)
87 .child(self.title),
88 )
89 .child(h_flex().gap_1().children(self.actions)),
90 )
91 .when_some(self.subtitle, |header, subtitle| {
92 header.child(
93 div()
94 .text_sm()
95 .text_color(theme.muted_foreground)
96 .child(subtitle),
97 )
98 });
99
100 let body = v_flex()
101 .id(body_id)
102 .flex_1()
103 .min_h(px(0.))
104 .gap_2()
105 .px_3()
106 .py_3()
107 .overflow_y_scrollbar()
108 .children(self.children);
109
110 v_flex()
111 .size_full()
112 .bg(theme.background)
113 .child(header)
114 .child(body)
115 .when_some(self.footer, |panel, footer| {
116 panel.child(
117 div()
118 .px_3()
119 .py_2()
120 .border_t_1()
121 .border_color(theme.border)
122 .child(footer),
123 )
124 })
125 }
126}