website/src/layouts/Base.astro
2026-09-09 20:09:07 -04:00

183 lines
5.8 KiB
Plaintext

---
import "../styles/global.css";
import { site } from "../data/site";
import Egg from "../components/Egg.astro";
import { Icon } from "astro-icon/components";
interface Props {
title?: string;
description?: string;
nav?: boolean;
}
const {
title = `${site.name} — ${site.tagline}`,
description = site.description,
nav = true,
} = Astro.props;
const path = Astro.url.pathname;
const canonical = new URL(path, `https://${site.domain}`).href;
const KAO_DEADLINE = "2027-01-01T00:00:00";
const kaoMs = new Date(KAO_DEADLINE).getTime() - Date.now();
const kaoCount = kaoMs > 0 ? `${Math.floor(kaoMs / 86_400_000)}d` : "in effect";
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
{path.startsWith("/admin") && <meta name="robots" content="noindex, nofollow" />}
<link rel="icon" href="/favicon.ico" sizes="32x32" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="color-scheme" content="dark" />
<meta name="theme-color" content="#1b1a18" />
{
path === "/" && (
<>
<link rel="preconnect" href="https://assets.hardcover.app" crossorigin />
<link rel="preconnect" href="https://i.scdn.co" crossorigin />
</>
)
}
<script is:inline>
try {
if (localStorage.getItem("kao-ribbon") === "off")
document.documentElement.dataset.ribbon = "off";
} catch (e) {}
</script>
<meta property="og:type" content="website" />
<meta property="og:site_name" content={site.domain} />
<meta property="og:url" content={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={`https://${site.domain}/og-image.png`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={`https://${site.domain}/og-image.png`} />
</head>
<body>
<a class="skip" href="#main">skip to content</a>
<div class="ribbon">
<a
class="ribbon__link"
href="https://keepandroidopen.org/"
target="_blank"
rel="noopener"
data-umami-event="ribbon"
data-umami-event-to="keepandroidopen"
>
<span class="ribbon__dot" aria-hidden="true"></span>
<span class="ribbon__text">keep android open</span>
<span class="ribbon__sub"
>&#8212;&nbsp;<span
class="ribbon__count"
data-kao-count
data-kao-deadline={KAO_DEADLINE}>{kaoCount}</span
></span
>
<span class="ribbon__arw" aria-hidden="true">&#8599;</span>
</a>
<button
class="ribbon__x"
type="button"
data-ribbon-dismiss
aria-label="dismiss"
>&#10005;</button>
</div>
{
nav && (
<header class="topbar">
<a class="mark" href="/">{site.wordmark}</a>
<nav class="topnav" aria-label="primary">
<a href="/projects" aria-current={path.startsWith("/projects") ? "page" : undefined}>
projects
</a>
<a href="/notes" aria-current={path.startsWith("/notes") ? "page" : undefined}>
notes
</a>
<a href="/contact" aria-current={path.startsWith("/contact") ? "page" : undefined}>
contact
</a>
</nav>
</header>
)
}
<main id="main">
<slot />
<p class="colophon">
<span class="version">{site.version}</span>
<Egg
note="third full version of the site, this ones a complete ui rebuild (still on cf workers, always)."
/>
</p>
<p class="srcline">
<a
href="https://git.zachy.cc/zach/website/"
target="_blank"
rel="noopener"
data-umami-event="src"
>
<Icon class="srcline__icon" name="ph:git-branch" aria-hidden="true" />
source &#8599;
</a>
</p>
</main>
<script>
const mark = document.querySelector(".mark");
const still = window.matchMedia("(prefers-reduced-motion: reduce)");
if (mark && !still.matches) {
const sweep = () => {
mark.classList.add("is-sweeping");
setTimeout(() => mark.classList.remove("is-sweeping"), 1200);
setTimeout(sweep, 9000 + Math.random() * 13000);
};
setTimeout(sweep, 4000 + Math.random() * 4000);
}
document
.querySelector("[data-ribbon-dismiss]")
?.addEventListener("click", () => {
document.querySelector(".ribbon")?.remove();
try {
localStorage.setItem("kao-ribbon", "off");
} catch (e) {}
});
const kaoEl = document.querySelector("[data-kao-count]");
if (kaoEl instanceof HTMLElement && kaoEl.dataset.kaoDeadline) {
const target = new Date(kaoEl.dataset.kaoDeadline).getTime();
const tick = () => {
const d = target - Date.now();
if (d <= 0) {
kaoEl.textContent = "in effect";
return true;
}
const days = Math.floor(d / 86400000);
const hrs = Math.floor((d % 86400000) / 3600000);
const min = Math.floor((d % 3600000) / 60000);
const sec = Math.floor((d % 60000) / 1000);
kaoEl.textContent = `${days}d ${hrs}h ${min}m ${sec}s`;
return false;
};
if (!tick()) {
const iv = setInterval(() => {
if (tick()) clearInterval(iv);
}, 1000);
}
}
</script>
</body>
</html>