diff --git a/web/src/app.css b/web/src/app.css index cb87428..c1465f0 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -204,3 +204,30 @@ body { .os-scrollbar-handle { border-radius: 4px; } + +/* View Transitions API - page transition animations */ +@keyframes page-fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes page-fade-out { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +::view-transition-old(root) { + animation: page-fade-out 120ms ease-out; +} + +::view-transition-new(root) { + animation: page-fade-in 150ms ease-in 50ms; +} diff --git a/web/src/app.html b/web/src/app.html index b3b7498..ade4086 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -3,6 +3,17 @@ + %sveltekit.head% diff --git a/web/src/lib/components/AppWrapper.svelte b/web/src/lib/components/AppWrapper.svelte index df21b1e..84ce400 100644 --- a/web/src/lib/components/AppWrapper.svelte +++ b/web/src/lib/components/AppWrapper.svelte @@ -1,31 +1,34 @@ -
- + +{#if bgColor} +
+{/if} +
{ + // Skip transitions for same-page navigations or if API not supported + if ( + !document.startViewTransition || + navigation.from?.url.pathname === navigation.to?.url.pathname + ) { + return; + } + + return new Promise((resolve) => { + document.startViewTransition(async () => { + resolve(); + await navigation.complete; + }); + }); + }); + onMount(() => { // Initialize theme store themeStore.init(); @@ -63,4 +91,13 @@ + +{#if showGlobalBackground} +
+ +{/if} + + {@render children()} diff --git a/web/svelte.config.js b/web/svelte.config.js index 86bd51d..ea7a43b 100644 --- a/web/svelte.config.js +++ b/web/svelte.config.js @@ -4,7 +4,7 @@ import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; /** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: vitePreprocess(), - inlineStyleThreshold: 1000, + inlineStyleThreshold: 2000, kit: { adapter: adapter({ out: "build",