Initial commit from Astro

This commit is contained in:
houston[bot]
2026-01-29 10:17:40 +01:00
committed by vorpax
commit c29b05bff3
123 changed files with 12279 additions and 0 deletions

169
src/components/Header.astro Normal file
View File

@@ -0,0 +1,169 @@
---
import IconX from "@/assets/icons/IconX.svg";
import IconMoon from "@/assets/icons/IconMoon.svg";
import IconSearch from "@/assets/icons/IconSearch.svg";
import IconArchive from "@/assets/icons/IconArchive.svg";
import IconSunHigh from "@/assets/icons/IconSunHigh.svg";
import IconMenuDeep from "@/assets/icons/IconMenuDeep.svg";
import LinkButton from "./LinkButton.astro";
import { SITE } from "@/config";
const { pathname } = Astro.url;
// Remove trailing slash from current pathname if exists
const currentPath =
pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
const isActive = (path: string) => {
const currentPathArray = currentPath.split("/").filter(p => p.trim());
const pathArray = path.split("/").filter(p => p.trim());
return currentPath === path || currentPathArray[0] === pathArray[0];
};
---
<a
id="skip-to-content"
href="#main-content"
class="absolute start-16 -top-full z-50 bg-background px-3 py-2 text-accent backdrop-blur-lg transition-all focus:top-4"
>
Skip to content
</a>
<header
class="app-layout flex flex-col items-center justify-between sm:flex-row"
>
<div
id="top-nav-wrap"
class:list={[
"py-4 sm:py-6",
"border-b border-border",
"relative w-full bg-background",
"flex items-baseline justify-between sm:items-center",
]}
>
<a
href="/"
class="absolute py-1 text-xl leading-8 font-semibold whitespace-nowrap sm:static sm:my-auto sm:text-2xl sm:leading-none"
>
{SITE.title}
</a>
<nav
id="nav-menu"
class="flex w-full flex-col items-center sm:ms-2 sm:flex-row sm:justify-end sm:space-x-4 sm:py-0"
>
<button
id="menu-btn"
class="focus-outline self-end p-2 sm:hidden"
aria-label="Open Menu"
aria-expanded="false"
aria-controls="menu-items"
>
<IconX id="close-icon" class="hidden" />
<IconMenuDeep id="menu-icon" />
</button>
<ul
id="menu-items"
class:list={[
"mt-4 grid w-44 grid-cols-2 place-content-center gap-2",
"[&>li>a]:block [&>li>a]:px-4 [&>li>a]:py-3 [&>li>a]:text-center [&>li>a]:font-medium [&>li>a]:hover:text-accent sm:[&>li>a]:px-2 sm:[&>li>a]:py-1",
"hidden",
"sm:mt-0 sm:flex sm:w-auto sm:gap-x-5 sm:gap-y-0",
]}
>
<li class="col-span-2">
<a href="/posts" class:list={{ "active-nav": isActive("/posts") }}>
Posts
</a>
</li>
<li class="col-span-2">
<a href="/tags" class:list={{ "active-nav": isActive("/tags") }}>
Tags
</a>
</li>
<li class="col-span-2">
<a href="/about" class:list={{ "active-nav": isActive("/about") }}>
About
</a>
</li>
{
SITE.showArchives && (
<li class="col-span-2">
<LinkButton
href="/archives"
class:list={[
"focus-outline flex justify-center p-3 sm:p-1",
{
"active-nav [&>svg]:stroke-accent": isActive("/archives"),
},
]}
title="Archives"
aria-label="archives"
>
<IconArchive class="hidden sm:inline-block" />
<span class="sm:sr-only">Archives</span>
</LinkButton>
</li>
)
}
<li class="col-span-1 flex items-center justify-center">
<LinkButton
href="/search"
class:list={[
"focus-outline flex p-3 sm:p-1",
{ "[&>svg]:stroke-accent": isActive("/search") },
]}
title="Search"
aria-label="search"
>
<IconSearch />
<span class="sr-only">Search</span>
</LinkButton>
</li>
{
SITE.lightAndDarkMode && (
<li class="col-span-1 flex items-center justify-center">
<button
id="theme-btn"
class="focus-outline relative size-12 p-4 sm:size-8 hover:[&>svg]:stroke-accent"
title="Toggles light & dark"
aria-label="auto"
aria-live="polite"
>
<IconMoon class="absolute top-[50%] left-[50%] -translate-[50%] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<IconSunHigh class="absolute top-[50%] left-[50%] -translate-[50%] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
</button>
</li>
)
}
</ul>
</nav>
</div>
</header>
<script>
function toggleNav() {
const menuBtn = document.querySelector("#menu-btn");
const menuItems = document.querySelector("#menu-items");
const menuIcon = document.querySelector("#menu-icon");
const closeIcon = document.querySelector("#close-icon");
if (!menuBtn || !menuItems || !menuIcon || !closeIcon) return;
menuBtn.addEventListener("click", () => {
const openMenu = menuBtn.getAttribute("aria-expanded") === "true";
menuBtn.setAttribute("aria-expanded", openMenu ? "false" : "true");
menuBtn.setAttribute("aria-label", openMenu ? "Open Menu" : "Close Menu");
menuItems.classList.toggle("hidden");
menuIcon.classList.toggle("hidden");
closeIcon.classList.toggle("hidden");
});
}
toggleNav();
// Runs on view transitions navigation
document.addEventListener("astro:after-swap", toggleNav);
</script>