Nye-TeeOff/frontend/src/components/Header.tsx
2026-04-13 13:51:11 +02:00

311 lines
12 KiB
TypeScript

"use client";
import Image from "next/image";
import Link from "next/link";
import { useState } from "react";
type NavItem = {
href: string;
label: string;
external?: boolean;
};
const placeGroups = [
{
label: "Hele Norge",
items: [{ href: "/sted/norge", label: "Hele Norge" }],
},
{
label: "Nord-Norge",
items: [
{ href: "/sted/nord-norge", label: "Nord-Norge" },
{ href: "/sted/finnmark", label: "Finnmark" },
{ href: "/sted/troms", label: "Troms" },
{ href: "/sted/nordland", label: "Nordland" },
],
},
{
label: "Midt-Norge",
items: [
{ href: "/sted/midt-norge", label: "Midt-Norge" },
{ href: "/sted/nord-trondelag", label: "Nord-Trøndelag" },
{ href: "/sted/sor-trondelag", label: "Sør-Trøndelag" },
{ href: "/sted/trondelag", label: "Trøndelag" },
],
},
{
label: "Vestlandet",
items: [
{ href: "/sted/vestlandet", label: "Vestlandet" },
{ href: "/sted/more-og-romsdal", label: "Møre og Romsdal" },
{ href: "/sted/sogn-og-fjordane", label: "Sogn og Fjordane" },
{ href: "/sted/hordaland", label: "Hordaland" },
{ href: "/sted/rogaland", label: "Rogaland" },
{ href: "/sted/vestland", label: "Vestland" },
],
},
{
label: "Sørlandet",
items: [
{ href: "/sted/sorlandet", label: "Sørlandet" },
{ href: "/sted/vest-agder", label: "Vest-Agder" },
{ href: "/sted/aust-agder", label: "Aust-Agder" },
{ href: "/sted/agder", label: "Agder" },
],
},
{
label: "Østlandet",
items: [
{ href: "/sted/ostlandet", label: "Østlandet" },
{ href: "/sted/telemark", label: "Telemark" },
{ href: "/sted/vestfold", label: "Vestfold" },
{ href: "/sted/ostfold", label: "Østfold" },
{ href: "/sted/buskerud", label: "Buskerud" },
{ href: "/sted/hedmark", label: "Hedmark" },
{ href: "/sted/oppland", label: "Oppland" },
{ href: "/sted/oslo-og-akershus", label: "Oslo og Akershus" },
{ href: "/sted/akershus", label: "Akershus" },
{ href: "/sted/oslo", label: "Oslo" },
],
},
];
const primaryNavItems: NavItem[] = [
{ href: "/medlemskap", label: "Medlemskap" },
{ href: "/vtg", label: "VTG" },
{ href: "/banebesok", label: "Banebesøk" },
];
const resourceNavItems: NavItem[] = [
{ href: "/turneringer", label: "Turneringer" },
{ href: "/klubbnummer", label: "Klubbnummer" },
{ href: "https://golfquiz.no", label: "Golfquiz.no", external: true },
{ href: "https://golfbox.golf", label: "Golfbox", external: true },
{ href: "/om", label: "FAQ / Om" },
{ href: "/kontakt", label: "Kontakt" },
];
export default function Header() {
const [isOpen, setIsOpen] = useState(false);
const [isPlacesOpen, setIsPlacesOpen] = useState(false);
const [isResourcesOpen, setIsResourcesOpen] = useState(false);
const closeAllMenus = () => {
setIsOpen(false);
setIsPlacesOpen(false);
setIsResourcesOpen(false);
};
return (
<header className="sticky top-0 z-[2000] border-b border-white/10 bg-[#25312A]/95 text-white shadow-sm backdrop-blur-md">
<div className="mx-auto flex h-20 max-w-[1400px] items-center justify-between px-4 sm:px-6 lg:px-8">
<Link href="/" className="h-10 transition-transform hover:scale-[1.02] active:scale-95 md:h-12">
<Image
src="/TeeOff-logo-Retina-1.png"
alt="TeeOff.no"
width={336}
height={102}
priority
className="h-full w-auto object-contain"
/>
</Link>
<nav className="hidden items-center gap-8 text-[12px] font-extrabold uppercase tracking-[0.14em] text-white/90 md:flex">
<div
className="group relative"
onMouseEnter={() => setIsPlacesOpen(true)}
onMouseLeave={() => setIsPlacesOpen(false)}
>
<button
type="button"
className="flex items-center gap-2 text-[12px] font-extrabold uppercase tracking-[0.14em] transition hover:text-[#8BC34A]"
onClick={() => {
setIsPlacesOpen((current) => !current);
setIsResourcesOpen(false);
}}
aria-expanded={isPlacesOpen}
>
<span>Steder</span>
<span className={`text-[10px] transition ${isPlacesOpen ? "rotate-180" : ""}`}></span>
</button>
{isPlacesOpen && (
<div className="absolute right-0 top-full z-[2100] w-[44rem] pt-4">
<div className="max-h-[min(70vh,42rem)] overflow-y-auto rounded-[1.75rem] border border-white/10 bg-[#25312A] p-5 shadow-2xl">
<div className="grid grid-cols-2 gap-5 xl:grid-cols-3">
{placeGroups.map((group) => (
<div key={group.label}>
<p className="mb-3 text-[10px] font-extrabold uppercase tracking-[0.2em] text-[#8BC34A]">
{group.label}
</p>
<div className="space-y-2">
{group.items.map((item) => (
<Link
key={item.href}
href={item.href}
className="block text-[13px] font-bold normal-case tracking-normal text-white/88 transition hover:text-[#FF5722]"
onClick={() => setIsPlacesOpen(false)}
>
{item.label}
</Link>
))}
</div>
</div>
))}
</div>
</div>
</div>
)}
</div>
{primaryNavItems.map((item) => (
<Link key={item.href} href={item.href} className="transition hover:text-[#8BC34A]">
{item.label}
</Link>
))}
<div
className="group relative"
onMouseEnter={() => setIsResourcesOpen(true)}
onMouseLeave={() => setIsResourcesOpen(false)}
>
<button
type="button"
className="flex items-center gap-2 text-[12px] font-extrabold uppercase tracking-[0.14em] transition hover:text-[#8BC34A]"
onClick={() => {
setIsResourcesOpen((current) => !current);
setIsPlacesOpen(false);
}}
aria-expanded={isResourcesOpen}
>
<span>Ressurser</span>
<span className={`text-[10px] transition ${isResourcesOpen ? "rotate-180" : ""}`}></span>
</button>
{isResourcesOpen && (
<div className="absolute right-0 top-full z-[2100] w-[20rem] pt-4">
<div className="rounded-[1.75rem] border border-white/10 bg-[#25312A] p-5 shadow-2xl">
<p className="mb-3 text-[10px] font-extrabold uppercase tracking-[0.2em] text-[#8BC34A]">
Ressurser
</p>
<div className="space-y-2">
{resourceNavItems.map((item) =>
item.external ? (
<a
key={item.href}
href={item.href}
target="_blank"
rel="noreferrer"
className="flex items-center justify-between text-[13px] font-bold normal-case tracking-normal text-white/88 transition hover:text-[#FF5722]"
onClick={() => setIsResourcesOpen(false)}
>
<span>{item.label}</span>
<span aria-hidden="true"></span>
</a>
) : (
<Link
key={item.href}
href={item.href}
className="block text-[13px] font-bold normal-case tracking-normal text-white/88 transition hover:text-[#FF5722]"
onClick={() => setIsResourcesOpen(false)}
>
{item.label}
</Link>
),
)}
</div>
</div>
</div>
)}
</div>
</nav>
<button onClick={() => setIsOpen(!isOpen)} className="p-2 text-white md:hidden" aria-label="Meny">
<div className="mb-1.5 h-0.5 w-6 bg-current transition-all"></div>
<div className="mb-1.5 h-0.5 w-6 bg-current"></div>
<div className="h-0.5 w-6 bg-current"></div>
</button>
</div>
{isOpen && (
<div className="absolute left-0 top-20 max-h-[calc(100vh-5rem)] w-full overflow-y-auto border-b border-white/10 bg-[#25312A] px-6 py-6 shadow-2xl md:hidden">
<div className="flex flex-col gap-5 pb-6">
<div className="border-b border-white/10 pb-5">
<Link
onClick={closeAllMenus}
href="/sted/norge"
className="block text-lg font-extrabold uppercase tracking-[0.08em] text-white"
>
Steder
</Link>
<div className="mt-4 grid gap-4">
{placeGroups.map((group) => (
<div key={group.label}>
<p className="mb-2 text-[10px] font-extrabold uppercase tracking-[0.2em] text-[#8BC34A]">
{group.label}
</p>
<div className="space-y-2">
{group.items.map((item) => (
<Link
key={item.href}
onClick={closeAllMenus}
href={item.href}
className="block text-sm font-bold text-white/88"
>
{item.label}
</Link>
))}
</div>
</div>
))}
</div>
</div>
{primaryNavItems.map((item) => (
<Link
key={item.href}
onClick={closeAllMenus}
href={item.href}
className="text-lg font-extrabold uppercase tracking-[0.08em] text-white"
>
{item.label}
</Link>
))}
<div className="border-t border-white/10 pt-5">
<p className="text-[10px] font-extrabold uppercase tracking-[0.2em] text-[#8BC34A]">
Ressurser
</p>
<div className="mt-4 flex flex-col gap-4">
{resourceNavItems.map((item) =>
item.external ? (
<a
key={item.href}
href={item.href}
target="_blank"
rel="noreferrer"
className="flex items-center justify-between text-sm font-bold text-white/88"
onClick={closeAllMenus}
>
<span>{item.label}</span>
<span aria-hidden="true"></span>
</a>
) : (
<Link
key={item.href}
onClick={closeAllMenus}
href={item.href}
className="text-sm font-bold text-white/88"
>
{item.label}
</Link>
),
)}
</div>
</div>
</div>
</div>
)}
</header>
);
}