mirror of
https://github.com/penpot/penpot.git
synced 2026-08-05 20:38:38 +00:00
🎉 Add loading pencil on heavy page loading and transition
This commit is contained in:
parent
10147b6abd
commit
86f7786db6
@ -24,6 +24,7 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||
[app.main.ui.flex-controls :as mfc]
|
||||
[app.main.ui.hooks :as ui-hooks]
|
||||
[app.main.ui.measurements :as msr]
|
||||
@ -155,6 +156,12 @@
|
||||
:pointer-events "none"
|
||||
:clip-path clip-path}}])))
|
||||
|
||||
;; Minimum loading time (ms) before the viewport pencil loader is shown.
|
||||
;; Loads shorter than this never display the loader, avoiding a flash.
|
||||
;; Page switches use a longer threshold since they're usually quick.
|
||||
(def ^:private viewport-loader-delay 300)
|
||||
(def ^:private viewport-loader-delay-page-switch 2000)
|
||||
|
||||
(mf/defc viewport*
|
||||
[{:keys [selected wglobal layout file page palete-size]}]
|
||||
(let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check
|
||||
@ -210,6 +217,7 @@
|
||||
space? (mf/use-state false)
|
||||
z? (mf/use-state false)
|
||||
cursor (mf/use-state (utils/get-cursor :pointer-inner))
|
||||
show-loader? (mf/use-state false)
|
||||
hover-ids (mf/use-state nil)
|
||||
hover (mf/use-state nil)
|
||||
measure-hover (mf/use-state nil)
|
||||
@ -219,6 +227,7 @@
|
||||
active-frames (mf/use-state #{})
|
||||
canvas-init? (mf/use-state false)
|
||||
initialized? (mf/use-state false)
|
||||
page-switch?* (mf/use-ref false)
|
||||
dragging-guide-id* (mf/use-state nil)
|
||||
guide-hover-axis* (mf/use-state nil)
|
||||
|
||||
@ -433,7 +442,27 @@
|
||||
preview-blend (-> refs/workspace-preview-blend
|
||||
(mf/deref))
|
||||
shapes-loading? (mf/deref wasm.api/shapes-loading?)
|
||||
transition-image (mf/deref wasm.api/transition-image*)]
|
||||
transition-image (mf/deref wasm.api/transition-image*)
|
||||
loading? (or page-transition? context-loss-overlay? shapes-loading?)]
|
||||
|
||||
(mf/with-effect []
|
||||
(when page-transition?
|
||||
(mf/set-ref-val! page-switch?* true))
|
||||
nil)
|
||||
|
||||
(mf/with-effect [page-transition?]
|
||||
(when-not page-transition?
|
||||
(mf/set-ref-val! page-switch?* false))
|
||||
nil)
|
||||
|
||||
(mf/with-effect [loading?]
|
||||
(if loading?
|
||||
(let [delay (if (mf/ref-val page-switch?*)
|
||||
viewport-loader-delay-page-switch
|
||||
viewport-loader-delay)
|
||||
timeout-id (js/setTimeout #(reset! show-loader? true) delay)]
|
||||
(fn [] (js/clearTimeout timeout-id)))
|
||||
(reset! show-loader? false)))
|
||||
|
||||
;; NOTE: We need this page-id dependency to react to it and reset the
|
||||
;; canvas, even though we are not using `page-id` inside the hook.
|
||||
@ -673,6 +702,9 @@
|
||||
(dm/str "inset(" strip "px 0 0 " strip "px round "
|
||||
rulers/canvas-border-radius "px)")))}])
|
||||
|
||||
(when @show-loader?
|
||||
[:> loader* {:class (stl/css :viewport-loader)
|
||||
:overlay true}])
|
||||
|
||||
[:svg.viewport-controls
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
|
||||
@ -33,6 +33,28 @@
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.viewport-loader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
background-color: var(--color-background-secondary);
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
@keyframes viewport-loader-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0.35;
|
||||
}
|
||||
}
|
||||
|
||||
.context-lost {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
|
||||
@ -1712,9 +1712,6 @@
|
||||
(do
|
||||
(begin-shapes-loading!)
|
||||
(h/call wasm/internal-module "_begin_loading")
|
||||
;; NOTE: to render a loading overlay in the future
|
||||
;; (when-not on-shapes-ready
|
||||
;; (h/call wasm/internal-module "_render_loading_overlay"))
|
||||
(try
|
||||
(-> (set-objects-async shapes render-callback on-shapes-ready)
|
||||
(p/catch (fn [error]
|
||||
|
||||
@ -273,19 +273,6 @@ pub extern "C" fn end_loading() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Draw a full-screen loading overlay (background + "Loading…" text).
|
||||
/// Called from CLJS right after begin_loading so the user sees
|
||||
/// immediate feedback while shapes are being processed.
|
||||
/// NOTE:
|
||||
/// This is currently not being used, but it's set there for testing purposes on
|
||||
/// upcoming tasks
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn render_loading_overlay() -> Result<()> {
|
||||
get_render_state().render_loading_overlay();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn reset_canvas() -> Result<()> {
|
||||
|
||||
@ -940,41 +940,6 @@ impl RenderState {
|
||||
self.surfaces.invalidate_tile_cache();
|
||||
}
|
||||
|
||||
/// NOTE:
|
||||
/// This is currently not being used, but it's set there for testing purposes on
|
||||
/// upcoming tasks
|
||||
pub fn render_loading_overlay(&mut self) {
|
||||
let canvas = self.surfaces.canvas(SurfaceId::Backbuffer);
|
||||
let skia::ISize { width, height } = canvas.base_layer_size();
|
||||
|
||||
canvas.save();
|
||||
|
||||
// Full-screen background rect
|
||||
let rect = skia::Rect::from_wh(width as f32, height as f32);
|
||||
let mut bg_paint = skia::Paint::default();
|
||||
bg_paint.set_color(self.background_color);
|
||||
bg_paint.set_style(skia::PaintStyle::Fill);
|
||||
canvas.draw_rect(rect, &bg_paint);
|
||||
|
||||
// Centered "Loading…" text
|
||||
let mut text_paint = skia::Paint::default();
|
||||
text_paint.set_color(skia::Color::GRAY);
|
||||
text_paint.set_anti_alias(true);
|
||||
|
||||
let font = self.fonts.debug_font();
|
||||
// FIXME
|
||||
let text = "Loading…";
|
||||
let (text_width, _) = font.measure_str(text, None);
|
||||
let metrics = font.metrics();
|
||||
let text_height = metrics.1.cap_height;
|
||||
let x = (width as f32 - text_width) / 2.0;
|
||||
let y = (height as f32 + text_height) / 2.0;
|
||||
canvas.draw_str(text, skia::Point::new(x, y), font, &text_paint);
|
||||
|
||||
canvas.restore();
|
||||
self.flush_and_submit();
|
||||
}
|
||||
|
||||
pub fn apply_render_to_final_canvas(&mut self) -> Result<()> {
|
||||
// During interactive transforms we render tiles directly into Target; updating the cache
|
||||
// (snapshot -> atlas blit -> tiles.add) can force GPU stalls. Defer cache rebuild until
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user