Skip to main content

guise/overlay/
loading.rs

1//! `LoadingOverlay` — a dimming busy layer over a container.
2//!
3//! Stateless: render it as the **last child** of a `.relative()` container and
4//! flip [`LoadingOverlay::visible`]. While visible it fills the parent with
5//! the body color at 60% opacity, centers a [`Loader`], and occludes the mouse
6//! so the content underneath can't be interacted with.
7//!
8//! ```ignore
9//! div()
10//!     .relative() // required: the overlay is absolutely positioned
11//!     .child(form)
12//!     .child(LoadingOverlay::new().visible(self.saving))
13//! ```
14
15use gpui::prelude::*;
16use gpui::{div, px, App, IntoElement, Window};
17
18use crate::feedback::Loader;
19use crate::theme::theme;
20
21/// A busy overlay for one container. The Mantine `LoadingOverlay`.
22#[derive(IntoElement)]
23pub struct LoadingOverlay {
24    visible: bool,
25    loader: Option<Loader>,
26}
27
28impl LoadingOverlay {
29    pub fn new() -> Self {
30        LoadingOverlay {
31            visible: false,
32            loader: None,
33        }
34    }
35
36    /// Show or hide the overlay. Hidden renders nothing at all.
37    pub fn visible(mut self, visible: bool) -> Self {
38        self.visible = visible;
39        self
40    }
41
42    /// Replace the default centered [`Loader`] (e.g. to change variant/color).
43    pub fn loader(mut self, loader: Loader) -> Self {
44        self.loader = Some(loader);
45        self
46    }
47}
48
49impl Default for LoadingOverlay {
50    fn default() -> Self {
51        LoadingOverlay::new()
52    }
53}
54
55impl RenderOnce for LoadingOverlay {
56    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
57        if !self.visible {
58            return div().into_any_element();
59        }
60
61        let t = theme(cx);
62        let scrim = t.body().alpha(0.6);
63
64        div()
65            .id("guise-loading-overlay")
66            .occlude()
67            .absolute()
68            .top(px(0.0))
69            .left(px(0.0))
70            .size_full()
71            .flex()
72            .items_center()
73            .justify_center()
74            .bg(scrim)
75            .child(self.loader.unwrap_or_default())
76            .into_any_element()
77    }
78}