Replace Next.js 16 + React 19 with Astro 5. Same visual design, same deploy pipeline, zero client-side framework. - All components rewritten as .astro files - Dark mode via inline scripts (no React context) - Timeline animation via IntersectionObserver script - Nav active state computed at build time - Self-hosted Source Code Pro woff2 fonts - Drop Font Awesome (icons were never loaded) - Drop unused headshot PNG (1MB, unreferenced) - Fix pfSense hardware refs (Netgate 1100, not N100) - Output: 212KB static HTML vs 2.6MB before - JS shipped: ~700 bytes inline vs ~130KB React runtime
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
---
|
||||
const pathname = Astro.url.pathname;
|
||||
|
||||
const links = [
|
||||
{ href: "/", label: "tyler" },
|
||||
{ href: "/homelab/", label: "homelab" },
|
||||
{ href: "/projects/", label: "projects" },
|
||||
];
|
||||
---
|
||||
|
||||
<header class="sticky top-0 z-50 bg-[var(--color-surface)] border-b border-[var(--color-border)]">
|
||||
<nav class="max-w-[740px] mx-auto px-4ch h-11 flex items-center justify-between">
|
||||
<a
|
||||
href="/"
|
||||
class="font-mono text-sm font-bold text-[var(--color-text)] hover:text-[var(--color-text-label)]"
|
||||
>
|
||||
~/
|
||||
</a>
|
||||
|
||||
<ul class="flex items-center gap-2ch">
|
||||
{links.map(({ href, label }) => {
|
||||
const active = pathname === href || pathname === href.replace(/\/$/, "");
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
href={href}
|
||||
aria-current={active ? "page" : undefined}
|
||||
class:list={[
|
||||
"font-mono text-sm",
|
||||
active
|
||||
? "text-[var(--color-text)]"
|
||||
: "text-[var(--color-text-label)] hover:text-[var(--color-text)]",
|
||||
]}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
<li>
|
||||
<button
|
||||
data-theme-toggle
|
||||
aria-label="Switch to light mode"
|
||||
class="font-mono text-sm text-[var(--color-text-label)] hover:text-[var(--color-text)] cursor-pointer"
|
||||
>
|
||||
[light]
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
const btn = document.querySelector("[data-theme-toggle]") as HTMLButtonElement;
|
||||
|
||||
function update() {
|
||||
const isDark = document.documentElement.classList.contains("dark");
|
||||
btn.textContent = isDark ? "[light]" : "[dark]";
|
||||
btn.setAttribute(
|
||||
"aria-label",
|
||||
isDark ? "Switch to light mode" : "Switch to dark mode",
|
||||
);
|
||||
}
|
||||
|
||||
btn.addEventListener("click", () => {
|
||||
const next = !document.documentElement.classList.contains("dark");
|
||||
document.documentElement.classList.toggle("dark", next);
|
||||
localStorage.setItem("lerko96-dark-mode", String(next));
|
||||
update();
|
||||
});
|
||||
|
||||
update();
|
||||
</script>
|
||||
Reference in New Issue
Block a user