use gpui_kit::{
AnyElement, ElementId, FontWeight, InteractiveElement as _, IntoElement, ParentElement,
RenderOnce, SharedString, Styled as _, Window,
component::{ActiveTheme as _, h_flex, scroll::ScrollableElement as _, v_flex},
div,
prelude::FluentBuilder as _,
px,
};
#[derive(IntoElement)]
pub struct SidePanel {
id: SharedString,
title: SharedString,
subtitle: Option<SharedString>,
actions: Vec<AnyElement>,
children: Vec<AnyElement>,
footer: Option<AnyElement>,
}
impl SidePanel {
pub fn new(id: impl Into<SharedString>, title: impl Into<SharedString>) -> Self {
Self {
id: id.into(),
title: title.into(),
subtitle: None,
actions: Vec::new(),
children: Vec::new(),
footer: None,
}
}
pub fn subtitle(mut self, subtitle: impl Into<SharedString>) -> Self {
self.subtitle = Some(subtitle.into());
self
}
pub fn action(mut self, action: impl IntoElement) -> Self {
self.actions.push(action.into_any_element());
self
}
pub fn footer(mut self, footer: impl IntoElement) -> Self {
self.footer = Some(footer.into_any_element());
self
}
}
impl ParentElement for SidePanel {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for SidePanel {
fn render(self, _: &mut Window, cx: &mut gpui_kit::App) -> impl IntoElement {
let theme = cx.theme();
let body_id = ElementId::Name(format!("{}-body", self.id).into());
let header = v_flex()
.gap_1()
.px_3()
.py_3()
.border_b_1()
.border_color(theme.border)
.child(
h_flex()
.justify_between()
.gap_2()
.child(
div()
.text_lg()
.font_weight(FontWeight::SEMIBOLD)
.child(self.title),
)
.child(h_flex().gap_1().children(self.actions)),
)
.when_some(self.subtitle, |header, subtitle| {
header.child(
div()
.text_sm()
.text_color(theme.muted_foreground)
.child(subtitle),
)
});
let body = v_flex()
.id(body_id)
.flex_1()
.min_h(px(0.))
.gap_2()
.px_3()
.py_3()
.overflow_y_scrollbar()
.children(self.children);
v_flex()
.size_full()
.bg(theme.background)
.child(header)
.child(body)
.when_some(self.footer, |panel, footer| {
panel.child(
div()
.px_3()
.py_2()
.border_t_1()
.border_color(theme.border)
.child(footer),
)
})
}
}