feat(web): nav/slideshow view transitions and crossfade

Change-Id: I0a37b417ee4c247dcc93d442c976eede6a6a6964
This commit is contained in:
midzelis
2025-12-08 11:36:17 +00:00
parent 4957bb15d3
commit 682bbce88e
4 changed files with 451 additions and 19 deletions
+60
View File
@@ -23,3 +23,63 @@ export function startViewerTransition(
},
});
}
let activeOverlay: HTMLElement | undefined;
export function removeCrossfadeOverlay() {
if (activeOverlay) {
activeOverlay.remove();
activeOverlay = undefined;
}
}
export async function crossfadeViewerContent(updateFn: () => void | Promise<void>, duration = 200) {
const viewerContent = document.querySelector<HTMLElement>('[data-viewer-content]');
if (!viewerContent) {
await updateFn();
return;
}
removeCrossfadeOverlay();
const clone = viewerContent.cloneNode(true) as HTMLElement;
Object.assign(clone.style, {
position: 'absolute',
inset: '0',
zIndex: '1',
pointerEvents: 'none',
});
delete clone.dataset.viewerContent;
if (!viewerContent.parentElement) {
await updateFn();
return;
}
viewerContent.parentElement.append(clone);
activeOverlay = clone;
const ready = eventManager.untilNext('ViewerOpenTransitionReady');
await updateFn();
try {
await ready;
} catch {
clone.remove();
if (activeOverlay === clone) {
activeOverlay = undefined;
}
return;
}
const fadeOut = clone.animate([{ opacity: 1 }, { opacity: 0 }], {
duration,
easing: 'cubic-bezier(0.4, 0, 1, 1)',
fill: 'forwards',
});
void fadeOut.finished.then(() => {
clone.remove();
if (activeOverlay === clone) {
activeOverlay = undefined;
}
});
}