kh3_website/js/page-transitions.js

107 lines
3.9 KiB
JavaScript

// Page transition functionality
document.addEventListener("DOMContentLoaded", function () {
// Top/Bottom curtain transition system
const curtainTop =
document.getElementById("pageCurtainTop") ||
(() => {
const div = document.createElement("div");
div.id = "pageCurtainTop";
div.className =
"fixed inset-x-0 top-0 h-1/2 z-50 transform -translate-y-full transition-transform duration-600 ease-in-out";
div.style.background = "linear-gradient(0deg, #b03037, #8a252a)";
document.body.appendChild(div);
return div;
})();
const curtainBottom =
document.getElementById("pageCurtainBottom") ||
(() => {
const div = document.createElement("div");
div.id = "pageCurtainBottom";
div.className =
"fixed inset-x-0 bottom-0 h-1/2 z-50 transform translate-y-full transition-transform duration-600 ease-in-out";
div.style.background = "linear-gradient(180deg, #b03037, #8a252a)";
document.body.appendChild(div);
return div;
})();
// Add entrance animation class
document.body.style.animation = "pageEnter 0.6s ease-out";
document.querySelectorAll("a[data-trans]").forEach((a) => {
a.addEventListener("click", (e) => {
const href = a.getAttribute("href");
if (!href || href.startsWith("#")) return;
e.preventDefault();
// Collect elements that had delayed entrance and fade them out in reverse order
const animatedEls = Array.from(
document.querySelectorAll('[style*="animation-delay"]')
).map((el) => {
const m = (el.getAttribute("style") || "").match(
/animation-delay:\s*([0-9.]+)s/
);
const delay = m ? parseFloat(m[1]) : 0;
return { el, delay };
});
const sorted = animatedEls
.sort((a, b) => b.delay - a.delay)
.map((item, idx) => ({ ...item, order: idx }));
sorted.forEach((item) => {
setTimeout(() => {
item.el.style.animation = "staggerFadeOut 260ms ease-out forwards";
}, item.order * 50);
});
const totalStaggerTime = (sorted.length - 1) * 50 + 260 + 130;
setTimeout(() => {
// Crossfade + tiny zoom of the whole page (longer)
document.body.style.animation = "pageExit 900ms ease forwards";
setTimeout(() => {
location.href = href;
}, 920);
}, totalStaggerTime);
});
});
// Hide curtains and close nav just before page is cached (prevents blank back step)
window.addEventListener("pagehide", () => {
if (curtainTop) curtainTop.style.transform = "translateY(-100%)";
if (curtainBottom) curtainBottom.style.transform = "translateY(100%)";
const navEl = document.getElementById("navMenu");
const gridEl = document.getElementById("menuGrid");
if (navEl) navEl.classList.add("hidden");
const wrapEl = document.getElementById("menuWrap");
if (wrapEl) wrapEl.classList.remove("open");
});
// Handle back/forward navigation
window.addEventListener("pageshow", function (event) {
if (event.persisted) {
// Page was loaded from cache (back/forward)
window.location.reload();
}
});
// Ensure back/forward navigation (bfcache) shows a clean page
window.addEventListener("pageshow", () => {
const loadingScreen = document.getElementById("loadingScreen");
if (loadingScreen) {
loadingScreen.style.display = "none";
loadingScreen.style.opacity = "0";
}
const ct = document.getElementById("pageCurtainTop");
const cb = document.getElementById("pageCurtainBottom");
if (ct) ct.style.transform = "translateY(-100%)";
if (cb) cb.style.transform = "translateY(100%)";
// Close nav if it was left open and reset grid icon
const navMenuEl = document.getElementById("navMenu");
const wrapEl2 = document.getElementById("menuWrap");
if (navMenuEl) navMenuEl.classList.add("hidden");
if (wrapEl2) wrapEl2.classList.remove("open");
});
});