use std::rc::Rc;
use gpui_kit::component::{h_flex, v_flex, IconName};
use gpui_kit::prelude::FluentBuilder as _;
use gpui_kit::{div, px, AnyElement, App, Div, ElementId, FontWeight, IntoElement, ParentElement, RenderOnce, SharedString, Styled as _, Window};
pub use kitchen_ui::widgets::{icon_button, row, scrub_label, slider, stepper, swatch, AccentChanged, AccentPicker, EmptyState, MenuSelect, OnSlide, OnStep, Section, SCRUB_PX};
use super::theme::{self, color};
pub fn pane() -> Div {
div().rounded(px(theme::RADIUS_LG)).overflow_hidden().bg(color::panel())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Edge {
Left,
Right,
Bottom,
}
type OnToggle = Rc<dyn Fn(&mut Window, &mut App)>;
#[derive(IntoElement)]
pub struct PanelHeader {
id: ElementId,
title: SharedString,
edge: Edge,
extra: Option<AnyElement>,
open: bool,
on_hide: OnToggle,
}
pub const HEADER_HEIGHT: f32 = 29.;
impl PanelHeader {
pub fn new(id: impl Into<ElementId>, title: impl Into<SharedString>, edge: Edge, on_hide: impl Fn(&mut Window, &mut App) + 'static) -> Self {
Self { id: id.into(), title: title.into(), edge, extra: None, open: true, on_hide: Rc::new(on_hide) }
}
pub fn open(mut self, open: bool) -> Self {
self.open = open;
self
}
pub fn extra(mut self, extra: impl IntoElement) -> Self {
self.extra = Some(extra.into_any_element());
self
}
}
impl RenderOnce for PanelHeader {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
let Self { id, title, edge, extra, open, on_hide } = self;
let (icon, tip) = match (edge, open) {
(Edge::Left, _) => (IconName::PanelLeftClose, format!("Hide {title}")),
(Edge::Right, _) => (IconName::PanelRightClose, format!("Hide {title}")),
(Edge::Bottom, true) => (IconName::ChevronDown, format!("Hide {title}")),
(Edge::Bottom, false) => (IconName::ChevronUp, format!("Show {title}")),
};
let button = icon_button(id, icon, tip).on_click(move |_, window, cx| on_hide(window, cx));
let title = div().text_sm().font_weight(FontWeight::SEMIBOLD).child(title);
let left = edge == Edge::Left;
let (lead, trail) = if left { (Some(button), None) } else { (None, Some(button)) };
h_flex()
.flex_none()
.h(px(HEADER_HEIGHT))
.px_1()
.gap_1p5()
.border_b_1()
.border_color(color::border())
.children(lead)
.when(!left, |d| d.pl_2())
.child(title)
.children(extra)
.child(div().flex_1())
.children(trail)
}
}
pub fn rail(id: impl Into<ElementId>, title: &str, edge: Edge, on_show: impl Fn(&mut Window, &mut App) + 'static) -> impl IntoElement {
let icon = match edge {
Edge::Left => IconName::PanelLeftOpen,
Edge::Right => IconName::PanelRightOpen,
Edge::Bottom => IconName::ChevronUp,
};
let on_show = Rc::new(on_show);
v_flex()
.flex_none()
.w(px(30.))
.h_full()
.py_1()
.items_center()
.rounded(px(theme::RADIUS_LG))
.bg(color::panel())
.child(icon_button(id, icon, format!("Show {title}")).on_click(move |_, window, cx| on_show(window, cx)))
}