use gpui::prelude::*;
use gpui::{div, px, AnyElement, App, IntoElement, Window};
use crate::theme::theme;
type Content = Box<dyn Fn(&mut Window, &mut App) -> AnyElement + 'static>;
#[derive(IntoElement)]
pub struct AppShell {
header: Option<(f32, Content)>,
navbar: Option<(f32, Content)>,
aside: Option<(f32, Content)>,
footer: Option<(f32, Content)>,
children: Vec<AnyElement>,
}
impl AppShell {
pub fn new() -> Self {
AppShell {
header: None,
navbar: None,
aside: None,
footer: None,
children: Vec::new(),
}
}
pub fn header<E>(
mut self,
height: f32,
content: impl Fn(&mut Window, &mut App) -> E + 'static,
) -> Self
where
E: IntoElement,
{
self.header = Some((
height,
Box::new(move |window, cx| content(window, cx).into_any_element()),
));
self
}
pub fn navbar<E>(
mut self,
width: f32,
content: impl Fn(&mut Window, &mut App) -> E + 'static,
) -> Self
where
E: IntoElement,
{
self.navbar = Some((
width,
Box::new(move |window, cx| content(window, cx).into_any_element()),
));
self
}
pub fn aside<E>(
mut self,
width: f32,
content: impl Fn(&mut Window, &mut App) -> E + 'static,
) -> Self
where
E: IntoElement,
{
self.aside = Some((
width,
Box::new(move |window, cx| content(window, cx).into_any_element()),
));
self
}
pub fn footer<E>(
mut self,
height: f32,
content: impl Fn(&mut Window, &mut App) -> E + 'static,
) -> Self
where
E: IntoElement,
{
self.footer = Some((
height,
Box::new(move |window, cx| content(window, cx).into_any_element()),
));
self
}
}
impl Default for AppShell {
fn default() -> Self {
AppShell::new()
}
}
impl ParentElement for AppShell {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl RenderOnce for AppShell {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let t = theme(cx);
let body = t.body().hsla();
let surface = t.surface().hsla();
let border = t.border().hsla();
let mut root = div().size_full().flex().flex_col().bg(body);
if let Some((height, content)) = self.header {
root = root.child(
div()
.flex_none()
.w_full()
.h(px(height))
.flex()
.flex_col()
.overflow_hidden()
.bg(surface)
.border_b_1()
.border_color(border)
.child(content(window, cx)),
);
}
let mut middle = div().flex_1().min_h(px(0.0)).w_full().flex();
if let Some((width, content)) = self.navbar {
middle = middle.child(
div()
.flex_none()
.w(px(width))
.flex()
.flex_col()
.overflow_hidden()
.bg(surface)
.border_r_1()
.border_color(border)
.child(content(window, cx)),
);
}
middle = middle.child(
div()
.id("guise-appshell-main")
.flex_1()
.min_w(px(0.0))
.flex()
.flex_col()
.overflow_y_scroll()
.children(self.children),
);
if let Some((width, content)) = self.aside {
middle = middle.child(
div()
.flex_none()
.w(px(width))
.flex()
.flex_col()
.overflow_hidden()
.bg(surface)
.border_l_1()
.border_color(border)
.child(content(window, cx)),
);
}
root = root.child(middle);
if let Some((height, content)) = self.footer {
root = root.child(
div()
.flex_none()
.w_full()
.h(px(height))
.flex()
.flex_col()
.overflow_hidden()
.bg(surface)
.border_t_1()
.border_color(border)
.child(content(window, cx)),
);
}
root
}
}