Configurator->POST /api/orders, deposit fetches order + PATCH in_production, header nav reaches the new pages (no orphans). New pages: katalog, katalog/[id], kallor, portal, shared states. tsc 0, build green (13 routes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
121 lines
4.3 KiB
TypeScript
121 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useEffect, useState } from "react";
|
|
|
|
const NAV = [
|
|
{ label: "Katalog", href: "/katalog" },
|
|
{ label: "Så funkar det", href: "/#motorn" },
|
|
{ label: "Källor", href: "/kallor" },
|
|
{ label: "Priser", href: "/#priser" },
|
|
];
|
|
|
|
function Wordmark() {
|
|
return (
|
|
<Link href="/" className="group flex items-baseline gap-2">
|
|
<span className="text-xl font-semibold tracking-[-0.04em]">0pt</span>
|
|
<span
|
|
className="inline-block h-[5px] w-[5px] translate-y-[-2px] transition-transform duration-300 group-hover:translate-y-[-4px]"
|
|
style={{ backgroundColor: "var(--accent-red)" }}
|
|
/>
|
|
<span className="font-mono text-[10px] uppercase tracking-[0.22em] text-muted-foreground">
|
|
your data
|
|
</span>
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
export function Header() {
|
|
const [scrolled, setScrolled] = useState(false);
|
|
const [open, setOpen] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const onScroll = () => setScrolled(window.scrollY > 40);
|
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
onScroll();
|
|
return () => window.removeEventListener("scroll", onScroll);
|
|
}, []);
|
|
|
|
return (
|
|
<header
|
|
className="sticky top-0 z-50 border-b border-border transition-colors"
|
|
style={{
|
|
backgroundColor: scrolled ? "rgba(255,255,255,0.82)" : "var(--background)",
|
|
backdropFilter: scrolled ? "blur(8px)" : "none",
|
|
}}
|
|
>
|
|
<div className="mx-auto flex h-16 max-w-[80rem] items-center justify-between px-6">
|
|
<Wordmark />
|
|
|
|
<nav className="hidden items-center md:flex">
|
|
{NAV.map((n) => (
|
|
<Link
|
|
key={n.label}
|
|
href={n.href}
|
|
className="group relative px-4 py-2 font-mono text-[12px] uppercase tracking-[0.12em] text-muted-foreground transition-colors hover:text-foreground"
|
|
>
|
|
{n.label}
|
|
<span
|
|
aria-hidden
|
|
className="pointer-events-none absolute bottom-1 left-4 right-4 h-px origin-left scale-x-0 bg-foreground transition-transform duration-300 group-hover:scale-x-100"
|
|
/>
|
|
</Link>
|
|
))}
|
|
</nav>
|
|
|
|
<div className="hidden items-center md:flex">
|
|
<Link
|
|
href="/portal"
|
|
className="px-4 py-2 font-mono text-[12px] uppercase tracking-[0.12em] text-muted-foreground transition-colors hover:text-foreground"
|
|
>
|
|
Logga in
|
|
</Link>
|
|
<Link
|
|
href="/bestall"
|
|
className="ml-3 inline-flex items-center gap-2 bg-foreground px-5 py-2.5 font-mono text-[12px] uppercase tracking-[0.12em] text-background transition-colors hover:bg-[var(--accent-red)]"
|
|
>
|
|
Beställ
|
|
<span aria-hidden>→</span>
|
|
</Link>
|
|
</div>
|
|
|
|
<button
|
|
aria-label="Meny"
|
|
onClick={() => setOpen((v) => !v)}
|
|
className="flex h-9 w-9 items-center justify-center border border-border transition-colors hover:border-foreground md:hidden"
|
|
>
|
|
<span className="font-mono text-sm">{open ? "✕" : "≡"}</span>
|
|
</button>
|
|
</div>
|
|
|
|
{open ? (
|
|
<div className="border-t border-border bg-background md:hidden">
|
|
<div className="flex flex-col px-6 py-2">
|
|
{NAV.map((n, i) => (
|
|
<Link
|
|
key={n.label}
|
|
href={n.href}
|
|
onClick={() => setOpen(false)}
|
|
className="flex items-baseline justify-between border-b border-border py-4 font-mono text-[12px] uppercase tracking-[0.12em] text-muted-foreground transition-colors hover:text-foreground"
|
|
>
|
|
<span>{n.label}</span>
|
|
<span className="text-[10px] tabular-nums text-muted-foreground/50">
|
|
{String(i + 1).padStart(2, "0")}
|
|
</span>
|
|
</Link>
|
|
))}
|
|
<Link
|
|
href="/bestall"
|
|
onClick={() => setOpen(false)}
|
|
className="mt-4 flex items-center justify-center gap-2 bg-foreground px-5 py-3.5 font-mono text-[12px] uppercase tracking-[0.12em] text-background"
|
|
>
|
|
Beställ
|
|
<span aria-hidden>→</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</header>
|
|
);
|
|
}
|