diff --git a/web/src/library-switcher.ts b/web/src/library-switcher.ts index 60e9270e..5eaadcc2 100644 --- a/web/src/library-switcher.ts +++ b/web/src/library-switcher.ts @@ -15,6 +15,33 @@ export async function switchWithTransition( if (!container || !loading) return; + // View Transitions (native, where supported): the browser snapshots the + // old shelves, fetchFn swaps the DOM, and the two snapshots crossfade — + // no blank phase, no manual opacity choreography. The dim + spinner is + // shown before the snapshot and hidden inside the update, so the dim + // blends away as part of the crossfade. Browsers without the API fall + // through to the dim + fade sequence below. + const doc = document as Document & { + startViewTransition?: (updateCallback: () => void | Promise) => { + finished: Promise; + }; + }; + if (doc.startViewTransition) { + try { + loading.classList.remove("hidden"); + const transition = doc.startViewTransition(async () => { + await fetchFn(); + loading.classList.add("hidden"); + }); + await transition.finished; + } catch (error) { + loading.classList.add("hidden"); + showToast("Failed to load library", "error"); + console.error("Switch library error:", error); + } + return; + } + try { container.classList.add( "opacity-0",