first commit
Docker-Images bauen und veroeffentlichen / build-and-push (push) Failing after 1m32s

This commit is contained in:
Nick Szaunig committed 2026-09-27 06:06:56 +02:00
commit 59bb5a38a3
132 files changed
+19435

No files matched your search

+114
View File
@@ -0,0 +1,114 @@
"use client";
import { LazyMotion, domAnimation, m } from "motion/react";
import { useEffect, useRef, useState } from "react";
import { NAV_ITEMS } from "@/content/site";
export function SiteHeader() {
const [active, setActive] = useState<string | null>(null);
const [scrolled, setScrolled] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const menuButton = useRef<HTMLButtonElement>(null);
const firstLink = useRef<HTMLAnchorElement>(null);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 24);
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
// Markiert den Abschnitt, der gerade die Bildschirmmitte kreuzt.
useEffect(() => {
const sections = NAV_ITEMS.map((item) => document.getElementById(item.id)).filter(Boolean) as HTMLElement[];
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) if (entry.isIntersecting) setActive(entry.target.id);
},
{ rootMargin: "-45% 0px -50% 0px" },
);
sections.forEach((s) => observer.observe(s));
return () => observer.disconnect();
}, []);
useEffect(() => {
if (!menuOpen) return;
firstLink.current?.focus();
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") {
setMenuOpen(false);
menuButton.current?.focus();
}
};
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [menuOpen]);
return (
<header
className={`sticky top-0 z-40 transition-colors duration-300 ${scrolled ? "bg-plaster/92 shadow-[0_1px_0_var(--color-line)] backdrop-blur" : "bg-transparent"}`}
>
<a href="#inhalt" className="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-3 focus:z-50 focus:bg-paper focus:px-3 focus:py-2">
Zum Inhalt springen
</a>
<div className="container-edge flex h-16 items-center justify-between gap-6">
<a href="#top" className="display text-xl tracking-tight" aria-label="ARTISTA Modelcamp 2027, zum Seitenanfang">
ARTISTA <span className="font-sans text-sm text-stone">Modelcamp 2027</span>
</a>
<LazyMotion features={domAnimation}>
<nav aria-label="Abschnitte" className="hidden lg:block">
<ul className="flex items-center gap-6 text-[0.9375rem]">
{NAV_ITEMS.map((item) => (
<li key={item.id} className="relative">
<a
href={`#${item.id}`}
aria-current={active === item.id ? "location" : undefined}
className="block py-2 text-ink/80 hover:text-ink aria-[current]:text-ink"
>
{item.label}
</a>
{active === item.id && (
<m.span layoutId="nav-indicator" className="absolute inset-x-0 -bottom-0.5 h-px bg-rosso" transition={{ type: "spring", stiffness: 380, damping: 34 }} />
)}
</li>
))}
</ul>
</nav>
</LazyMotion>
<div className="flex items-center gap-3">
<a href="#preis" className="btn btn-primary hidden min-h-10 px-5 py-2 text-sm sm:inline-flex">
Platz buchen
</a>
<button
ref={menuButton}
type="button"
className="inline-flex h-11 items-center rounded-full border border-ink/30 px-4 text-sm font-semibold lg:hidden"
aria-expanded={menuOpen}
aria-controls="mobile-menu"
onClick={() => setMenuOpen((v) => !v)}
>
{menuOpen ? "Schließen" : "Menü"}
</button>
</div>
</div>
{menuOpen && (
<nav id="mobile-menu" aria-label="Abschnitte" className="border-t border-line bg-plaster lg:hidden">
<ul className="container-edge py-4">
{NAV_ITEMS.map((item, index) => (
<li key={item.id}>
<a
ref={index === 0 ? firstLink : undefined}
href={`#${item.id}`}
onClick={() => setMenuOpen(false)}
className="display block border-b border-line/70 py-3 text-2xl"
>
{item.label}
</a>
</li>
))}
</ul>
</nav>
)}
</header>
);
}