mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-09-22 15:22:59 +00:00
222 lines
7.6 KiB
TypeScript
222 lines
7.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import { Link, usePathname } from "@/i18n/routing";
|
|
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
|
|
|
// Icons
|
|
import { MdClose, MdMenu } from "react-icons/md";
|
|
|
|
import LanguageSwitcher from "./LanguageSwitcher";
|
|
|
|
// Shadcn UI
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
|
|
interface NavItem {
|
|
href:
|
|
| "/"
|
|
| "/ajakava"
|
|
| "/haldus"
|
|
| "/kodukord"
|
|
| "/messiala"
|
|
| "/piletid"
|
|
| "/striim"
|
|
| "/turniirid";
|
|
label: string;
|
|
}
|
|
|
|
interface HeaderProps {
|
|
navItems: NavItem[];
|
|
}
|
|
|
|
const Header = ({ navItems }: HeaderProps) => {
|
|
const pathname = usePathname();
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
|
|
// Header navigation should include all options except homepage and hidden items
|
|
const hiddenNavHrefs: NavItem["href"][] = ["/messiala", "/ajakava"];
|
|
const mainNavItems = navItems.filter(
|
|
(item) => item.href !== "/" && !hiddenNavHrefs.includes(item.href),
|
|
);
|
|
const dropdownNavItems = mainNavItems;
|
|
|
|
const navIconByHref: Partial<Record<NavItem["href"], string>> = {
|
|
"/messiala": "weekend",
|
|
"/ajakava": "event_note",
|
|
"/piletid": "local_activity",
|
|
"/turniirid": "rewarded_ads",
|
|
"/kodukord": "gavel",
|
|
};
|
|
|
|
useEffect(() => {
|
|
const largeScreenQuery = window.matchMedia("(min-width: 1280px)");
|
|
|
|
const handleScaleOrViewportChange = (event: MediaQueryListEvent) => {
|
|
if (event.matches) {
|
|
setIsMobileMenuOpen(false);
|
|
}
|
|
};
|
|
|
|
if (largeScreenQuery.matches) {
|
|
setIsMobileMenuOpen(false);
|
|
}
|
|
|
|
largeScreenQuery.addEventListener("change", handleScaleOrViewportChange);
|
|
|
|
return () => {
|
|
largeScreenQuery.removeEventListener(
|
|
"change",
|
|
handleScaleOrViewportChange,
|
|
);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
setIsMobileMenuOpen(false);
|
|
}, [pathname]);
|
|
|
|
return (
|
|
<header className="px-4 sm:px-8 md:px-12 lg:px-16 py-3 flex items-center bg-[#0E0F19] border-b-3 border-[#1F5673] justify-between">
|
|
{/* Logo */}
|
|
<Link href="/" className="shrink-0">
|
|
<Image
|
|
src="/tipilan-icon-white.svg"
|
|
alt="TipiLAN"
|
|
width={40}
|
|
height={40}
|
|
className="h-auto w-10"
|
|
/>
|
|
</Link>
|
|
|
|
{/* Right side - Navigation + controls */}
|
|
<div className="flex items-center gap-12">
|
|
{/* Desktop Navigation */}
|
|
<nav className="hidden xl:flex items-center gap-8">
|
|
{mainNavItems.map((item) => {
|
|
const isActive = pathname === item.href;
|
|
|
|
return (
|
|
<Link
|
|
key={item.href}
|
|
href={item.href}
|
|
aria-current={isActive ? "page" : undefined}
|
|
aria-disabled={isActive ? true : undefined}
|
|
tabIndex={isActive ? -1 : undefined}
|
|
className={`${vipnagorgialla.className} group font-bold italic leading-none text-lg uppercase px-4 py-2 border-4 border-[#00A3E0] transition ${
|
|
isActive
|
|
? "bg-[#00A3E0] text-black cursor-default pointer-events-none"
|
|
: "bg-[#1F5673] text-[#EEE5E5] hover:bg-[#00A3E0] hover:text-black"
|
|
}`}
|
|
>
|
|
{item.label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
<LanguageSwitcher />
|
|
|
|
{/* Mobile menu button */}
|
|
<DropdownMenu
|
|
open={isMobileMenuOpen}
|
|
onOpenChange={setIsMobileMenuOpen}
|
|
>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="xl:hidden size-10 cursor-pointer"
|
|
>
|
|
{isMobileMenuOpen ? (
|
|
<MdClose className="size-10 text-[#EEE5E5]" />
|
|
) : (
|
|
<MdMenu className="size-10 text-[#EEE5E5]" />
|
|
)}
|
|
<span className="sr-only">Menu</span>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent
|
|
align="end"
|
|
sideOffset={0}
|
|
className="xl:hidden w-screen sm:w-72 translate-x-0 sm:translate-x-4 translate-y-3 rounded-none border-3 border-[#1F5673] bg-[#0E0F19] p-0"
|
|
>
|
|
{dropdownNavItems.map((item, index) => {
|
|
const isActive = pathname === item.href;
|
|
const hasBottomBorder = index !== dropdownNavItems.length - 1;
|
|
|
|
return (
|
|
<DropdownMenuItem
|
|
key={item.href}
|
|
style={{ animationDelay: `${index * 55}ms` }}
|
|
className="p-0 opacity-0 animate-[dropdown-item-in_220ms_cubic-bezier(0.16,1,0.3,1)_forwards] focus:bg-transparent data-highlighted:bg-transparent"
|
|
>
|
|
{isActive ? (
|
|
<span
|
|
className={`${vipnagorgialla.className} block w-full cursor-default bg-[#00A3E0] px-5 py-2.5 text-xl font-bold italic leading-none uppercase text-black ${
|
|
hasBottomBorder ? "border-b-3 border-[#1F5673]" : ""
|
|
}`}
|
|
>
|
|
<span className="flex items-center justify-between gap-3">
|
|
<span>{item.label}</span>
|
|
{navIconByHref[item.href] ? (
|
|
<span
|
|
className="material-symbols-outlined text-[2rem]! leading-none"
|
|
style={
|
|
item.href === "/piletid"
|
|
? {
|
|
fontVariationSettings:
|
|
'"FILL" 0, "wght" 700, "GRAD" 0, "opsz" 24',
|
|
}
|
|
: undefined
|
|
}
|
|
>
|
|
{navIconByHref[item.href]}
|
|
</span>
|
|
) : null}
|
|
</span>
|
|
</span>
|
|
) : (
|
|
<Link
|
|
href={item.href}
|
|
className={`${vipnagorgialla.className} group block w-full bg-[#0E0F19] px-5 py-2.5 text-xl font-bold italic leading-none uppercase text-[#EEE5E5] transition hover:bg-[#00A3E0] hover:text-black ${
|
|
hasBottomBorder ? "border-b-3 border-[#1F5673]" : ""
|
|
}`}
|
|
>
|
|
<span className="flex items-center justify-between gap-3">
|
|
<span>{item.label}</span>
|
|
{navIconByHref[item.href] ? (
|
|
<span
|
|
className="material-symbols-outlined text-[2rem]! leading-none text-[#00A3E0] group-hover:text-black"
|
|
style={
|
|
item.href === "/piletid"
|
|
? {
|
|
fontVariationSettings:
|
|
'"FILL" 0, "wght" 700, "GRAD" 0, "opsz" 24',
|
|
}
|
|
: undefined
|
|
}
|
|
>
|
|
{navIconByHref[item.href]}
|
|
</span>
|
|
) : null}
|
|
</span>
|
|
</Link>
|
|
)}
|
|
</DropdownMenuItem>
|
|
);
|
|
})}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</header>
|
|
);
|
|
};
|
|
|
|
export default Header;
|