feat(ui): View Transitions crossfade for library switches
Where the browser supports it (Chrome 111+, Safari 18+, Firefox 139+), switchWithTransition now uses the native View Transitions API: the old shelves are snapshotted, the fetch + swap happen behind the dim, and the two snapshots crossfade — no blank phase, no manual opacity choreography. The dim + spinner is hidden inside the update so it blends away as part of the transition. Browsers without the API keep the existing dim + fade sequence unchanged. Zero dependencies — the crossfade is the browser's own.
This commit is contained in:
1 parent
a11b4a9cc4
commit
a31da89df5
1 file changed
+27
@@ -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<void>) => {
|
||||
finished: Promise<void>;
|
||||
};
|
||||
};
|
||||
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",
|
||||
|
||||
Reference in new issue
Block a user