use super::*;
pub(crate) fn scrim_alpha(alpha_dark: f32) -> gpui::Hsla {
theme::scrim(alpha_dark)
}
pub fn modal(
id: impl Into<ElementId>,
viewport: gpui::Size<Pixels>,
card: AnyElement,
on_dismiss: impl Fn(&gpui::MouseDownEvent, &mut gpui::Window, &mut gpui::App) + 'static,
) -> AnyElement {
modal_with(id, viewport, card, DIALOG_RADIUS, 0.6, on_dismiss)
}
pub fn modal_glass(
id: impl Into<ElementId>,
viewport: gpui::Size<Pixels>,
card: AnyElement,
on_dismiss: impl Fn(&gpui::MouseDownEvent, &mut gpui::Window, &mut gpui::App) + 'static,
) -> AnyElement {
modal_with(
id,
viewport,
card,
Theme::surface_radius(),
0.35,
on_dismiss,
)
}
pub(super) fn modal_with(
id: impl Into<ElementId>,
viewport: gpui::Size<Pixels>,
card: AnyElement,
corner_radius: f32,
scrim: f32,
on_dismiss: impl Fn(&gpui::MouseDownEvent, &mut gpui::Window, &mut gpui::App) + 'static,
) -> AnyElement {
let card = crate::surface::popover(corner_radius, card).into_any_element();
gpui::deferred(
gpui::anchored()
.position(gpui::point(px(0.0), px(0.0)))
.child(
div()
.occlude()
.w(viewport.width)
.h(viewport.height)
.bg(scrim_alpha(scrim))
.flex()
.items_center()
.justify_center()
.on_any_mouse_down(on_dismiss)
.child(crate::cover::cover())
.child(motion::dialog_in(id, div().occlude().child(card))),
),
)
.priority(MODAL_LAYER)
.into_any_element()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side {
Left,
Right,
Bottom,
}
impl Side {
fn axis(self) -> gpui::Axis {
match self {
Side::Left | Side::Right => gpui::Axis::Horizontal,
Side::Bottom => gpui::Axis::Vertical,
}
}
}
pub(super) const DIALOG_RADIUS: f32 = 16.0;
pub fn sheet_panel(theme: &Theme, side: Side) -> gpui::Div {
let card = div()
.size_full()
.flex()
.flex_col()
.shadow_lg()
.text_color(theme.text);
let card = match side {
Side::Left => card
.rounded_r(px(DIALOG_RADIUS))
.border_r_1()
.border_color(theme.border),
Side::Right => card
.rounded_l(px(DIALOG_RADIUS))
.border_l_1()
.border_color(theme.border),
Side::Bottom => card
.rounded_t(px(DIALOG_RADIUS))
.border_t_1()
.border_color(theme.border),
};
if theme.glass {
card.bg(theme.glass_overlay())
} else {
card.bg(theme.surface_overlay)
}
}
pub fn sheet(
id: impl Into<SharedString>,
viewport: gpui::Size<Pixels>,
side: Side,
extent: Pixels,
content: AnyElement,
closing: Option<web_time::Instant>,
on_dismiss: impl Fn(&gpui::ClickEvent, &mut gpui::Window, &mut gpui::App) + 'static,
) -> AnyElement {
let id = id.into();
let exit = closing.map(exit_progress);
let panel = div().absolute();
let panel = match side.axis() {
gpui::Axis::Horizontal => panel.top_0().bottom_0().w(extent),
gpui::Axis::Vertical => panel.left_0().right_0().h(extent),
};
let panel = panel.child(crate::surface::popover(DIALOG_RADIUS, content));
let seat = move |el: gpui::Div, t: f32| {
let inset = extent * (t - 1.0);
match side {
Side::Left => el.left(inset),
Side::Right => el.right(inset),
Side::Bottom => el.bottom(inset),
}
};
let panel = if let Some(t) = exit {
let panel = seat(panel, 1.0 - t).child(div().absolute().inset_0().occlude());
panel
.with_animation(
SharedString::from(format!("{id}-out")),
motion::MENU_OUT.animation(),
move |el, _| el,
)
.into_any_element()
} else {
panel
.with_animation(id.clone(), motion::DIALOG_IN.animation(), seat)
.into_any_element()
};
gpui::deferred(
gpui::anchored()
.position(gpui::point(px(0.0), px(0.0)))
.child(
div()
.id(SharedString::from(format!("{id}-scrim")))
.occlude()
.relative()
.w(viewport.width)
.h(viewport.height)
.bg(scrim_alpha(0.6 * (1.0 - exit.unwrap_or(0.0))))
.on_click(on_dismiss)
.child(crate::cover::cover())
.child(panel),
),
)
.priority(MODAL_LAYER)
.into_any_element()
}