aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/routes/+layout.svelte30
-rw-r--r--src/styles/motion.css22
2 files changed, 52 insertions, 0 deletions
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 8c36bb0f..e2cb4132 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -11,6 +11,7 @@ import HeadTitle from "$lib/Home/HeadTitle.svelte";
import "../app.css";
import { readable, type Readable } from "svelte/store";
import { navigating } from "$app/stores";
+import { onNavigate } from "$app/navigation";
import NotificationsProvider from "$lib/Notification/NotificationsProvider.svelte";
import Root from "$lib/Home/Root.svelte";
import root from "$lib/Utility/root";
@@ -90,6 +91,34 @@ $: way = data.url.includes("/user")
$: if ($navigating) isMenuOpen = false;
+onNavigate((navigation) => {
+ if (!("startViewTransition" in document)) return;
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
+
+ const fromPath = navigation.from?.url.pathname ?? "/";
+ const toPath = navigation.to?.url.pathname ?? "/";
+ const direction = toPath.includes("/user")
+ ? 1
+ : fromPath.includes("/user")
+ ? -1
+ : navigationOrder.indexOf(toPath) > navigationOrder.indexOf(fromPath)
+ ? 1
+ : -1;
+
+ document.documentElement.style.setProperty("--vt-direction", String(direction));
+
+ return new Promise((resolve) => {
+ (
+ document as Document & {
+ startViewTransition: (cb: () => Promise<void>) => unknown;
+ }
+ ).startViewTransition(async () => {
+ resolve();
+ await navigation.complete;
+ });
+ });
+});
+
const handleScroll = () => {
const currentScrollPosition = window.scrollY;
@@ -437,6 +466,7 @@ $: {
position: sticky;
top: 1.25rem;
background-color: var(--base0011-strong);
+ view-transition-name: app-header;
transition: transform var(--duration-slow) var(--ease-out-quart);
}
diff --git a/src/styles/motion.css b/src/styles/motion.css
index 28de2180..857928d4 100644
--- a/src/styles/motion.css
+++ b/src/styles/motion.css
@@ -5,3 +5,25 @@
--duration-base: 0.24s;
--duration-slow: 0.4s;
}
+
+::view-transition-old(root) {
+ animation: vt-slide-out var(--duration-base) var(--ease-out-quart) both;
+}
+
+::view-transition-new(root) {
+ animation: vt-slide-in var(--duration-base) var(--ease-out-quart) both;
+}
+
+@keyframes vt-slide-out {
+ to {
+ transform: translateX(calc(var(--vt-direction, 1) * -200px));
+ opacity: 0;
+ }
+}
+
+@keyframes vt-slide-in {
+ from {
+ transform: translateX(calc(var(--vt-direction, 1) * 200px));
+ opacity: 0;
+ }
+}