cse-website/src/layouts/DefaultLayout.astro

111 lines
3.5 KiB
Text

---
import { Font } from 'astro:assets';
import { ClientRouter } from 'astro:transitions';
import BaseHead from '@/components/BaseHead.astro';
import Banner from '@/components/layout/banner';
import Footer from '@/components/layout/footer';
import Navbar from '@/components/layout/navbar';
const { title, description } = Astro.props;
const currentPath = Astro.url.pathname;
---
<html lang="en">
<head>
<ClientRouter />
<BaseHead title={title} description={description} />
<Font cssVariable="--font-imprima" preload />
<Font cssVariable="--font-rubik" preload />
<Font cssVariable="--font-eb-garamond" preload />
<meta name="view-transition" content="same-origin" />
</head>
<body class="h-screen antialiased flex flex-col">
<div
id="route-preloader"
class="pointer-events-none fixed inset-0 z-[1000] place-items-center bg-background/75 backdrop-blur-sm"
style="display: none; opacity: 0; transition: opacity 160ms ease;"
role="status"
aria-hidden="true"
aria-live="polite"
>
<div class="flex items-center gap-3 rounded-lg border bg-background px-4 py-3 shadow-lg">
<img
src="/images/publications-preloader.gif"
alt=""
width="48"
height="48"
class="size-8"
decoding="async"
/>
<span class="text-sm text-muted-foreground">Loading page...</span>
</div>
</div>
<Banner client:only="react" />
<Navbar currentPage={currentPath} client:only="react" />
<main class="flex-1" style="view-transition-name: main;">
<slot />
</main>
<Footer client:only="react" />
<script is:inline>
(() => {
if (window.__routePreloaderInitialized) return;
window.__routePreloaderInitialized = true;
const reducedMotionQuery = window.matchMedia(
"(prefers-reduced-motion: reduce)",
);
let showTimer;
let hideTimer;
let fallbackTimer;
const getRoutePreloader = () =>
document.getElementById("route-preloader");
const show = () => {
const routePreloader = getRoutePreloader();
if (!routePreloader) return;
window.clearTimeout(hideTimer);
routePreloader.style.display = "grid";
routePreloader.setAttribute("aria-hidden", "false");
requestAnimationFrame(() => {
routePreloader.style.opacity = "1";
});
};
const hide = () => {
const routePreloader = getRoutePreloader();
window.clearTimeout(showTimer);
window.clearTimeout(fallbackTimer);
if (!routePreloader) return;
routePreloader.style.opacity = "0";
routePreloader.setAttribute("aria-hidden", "true");
hideTimer = window.setTimeout(
() => {
getRoutePreloader()?.style.setProperty("display", "none");
},
reducedMotionQuery.matches ? 0 : 160,
);
};
const queue = () => {
window.clearTimeout(showTimer);
window.clearTimeout(fallbackTimer);
showTimer = window.setTimeout(show, 450);
fallbackTimer = window.setTimeout(hide, 8000);
};
document.addEventListener("astro:before-preparation", queue);
document.addEventListener("astro:after-swap", hide);
document.addEventListener("astro:page-load", hide);
window.addEventListener("load", hide);
window.addEventListener("pageshow", hide);
})();
</script>
</body>
</html>