317 lines
15 KiB
TypeScript
317 lines
15 KiB
TypeScript
"use client"
|
||
|
||
import Link from "next/link"
|
||
import { usePathname } from "next/navigation"
|
||
import { useState, useEffect } from "react"
|
||
import { cn } from "@/lib/utils"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Input } from "@/components/ui/input"
|
||
import Image from "next/image"
|
||
|
||
const allNavItems = [
|
||
{ href: "/", label: "ALL SPORTS" },
|
||
{ href: "/live", label: "LIVE" },
|
||
{ href: "/virtual", label: "VIRTUAL" },
|
||
{ href: "/special-games", label: "SPECIAL Games" },
|
||
{ href: "/multi-hot-5", label: "MULTI HOT 5" },
|
||
{ href: "/poker", label: "POKER", isNew: true },
|
||
{ href: "/race", label: "RACE", isNew: true },
|
||
{ href: "/promo", label: "PROMO" },
|
||
{ href: "/aviator", label: "AVIATOR" },
|
||
]
|
||
|
||
const drawerLinks = [
|
||
{ href: "/", label: "All Sports" },
|
||
{ href: "/live", label: "Live Betting" },
|
||
{ href: "/virtual", label: "Virtual" },
|
||
{ href: "/special-games", label: "Special Games" },
|
||
{ href: "/poker", label: "Poker" },
|
||
{ href: "/race", label: "Race" },
|
||
{ href: "/promo", label: "Promotions" },
|
||
{ href: "/deposit", label: "Deposit" },
|
||
{ href: "/bonus", label: "Bonus" },
|
||
{ href: "/rules", label: "Betting Rules" },
|
||
{ href: "/terms", label: "Terms & Conditions" },
|
||
]
|
||
|
||
interface SiteHeaderProps {
|
||
onLoginClick?: () => void
|
||
onRegisterClick?: () => void
|
||
}
|
||
|
||
export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
|
||
const pathname = usePathname()
|
||
const isLivePage = pathname === "/live"
|
||
const [time, setTime] = useState("")
|
||
const [prevPathname, setPrevPathname] = useState(pathname)
|
||
const [drawerOpen, setDrawerOpen] = useState(false)
|
||
|
||
// Adjust state during render when pathname changes
|
||
if (pathname !== prevPathname) {
|
||
setPrevPathname(pathname)
|
||
setDrawerOpen(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
const updateClock = () => {
|
||
setTime(new Date().toLocaleTimeString("en-GB", { hour12: false }))
|
||
}
|
||
const interval = setInterval(updateClock, 1000)
|
||
updateClock()
|
||
return () => clearInterval(interval)
|
||
}, [])
|
||
|
||
return (
|
||
<>
|
||
<header className="bg-brand-bg sticky top-0 z-50">
|
||
{/* ===== DESKTOP: Top bar (hidden on mobile) ===== */}
|
||
<div className="hidden md:flex bg-brand-surface px-3 py-1 items-center justify-between text-[11px] text-white">
|
||
<div className="flex items-center gap-4">
|
||
<button className="flex items-center gap-1.5 hover:text-primary transition-colors">
|
||
<Image
|
||
src="https://flagcdn.com/w20/gb.png"
|
||
alt="English"
|
||
width={20}
|
||
height={15}
|
||
className="rounded-sm"
|
||
unoptimized // Since it's an external image from a CDN
|
||
/>
|
||
<span className="font-bold flex items-center gap-1">en <span className="text-[8px]">▼</span></span>
|
||
</button>
|
||
<div className="flex items-center gap-2 font-bold">
|
||
<span className="text-[14px]">🕒</span>
|
||
<span className="tabular-nums">{time || "00:00:00"}</span>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-6">
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-white font-bold tracking-tight">+251 (0)
|
||
<Input type="password" placeholder="Password" className="bg-brand-surface-light border-none px-2 py-0.5 w-32 text-[11px] h-7 rounded-none shadow-none text-white placeholder:text-gray-500" />
|
||
</span>
|
||
<Input type="password" placeholder="Password" className="bg-brand-surface-light border-none px-2 py-0.5 w-32 text-[11px] h-7 rounded-none shadow-none text-white placeholder:text-gray-500" />
|
||
</div>
|
||
<div className="flex items-center gap-1">
|
||
<Button onClick={onLoginClick} className="bg-brand-primary text-white hover:bg-brand-primary-hover px-5 h-7 text-[11px] font-bold rounded-none uppercase">
|
||
Login
|
||
</Button>
|
||
<Button onClick={onRegisterClick} className="bg-brand-primary text-white hover:bg-brand-primary-hover px-5 h-7 text-[11px] font-bold rounded-none uppercase">
|
||
Sign Up
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* ===== MOBILE: Top bar (hidden on desktop) ===== */}
|
||
<div className="flex md:hidden items-center h-12 bg-brand-bg border-b border-white/5 px-2 gap-2">
|
||
{/* Hamburger */}
|
||
<button
|
||
onClick={() => setDrawerOpen(true)}
|
||
className="flex flex-col justify-center gap-[5px] p-2 shrink-0"
|
||
aria-label="Menu"
|
||
>
|
||
<span className="w-5 h-0.5 bg-white block" />
|
||
<span className="w-5 h-[2px] bg-white block" />
|
||
<span className="w-5 h-[2px] bg-white block" />
|
||
</button>
|
||
|
||
{/* Logo (centered, grows to fill) */}
|
||
<Link href="/" className="flex-1 flex items-center justify-center">
|
||
<div className="flex items-center">
|
||
<div className="bg-brand-accent px-2 py-0.5 -skew-x-12 flex items-center h-[28px]">
|
||
<span className="text-xl font-black text-white italic tracking-tighter skew-x-12 leading-none">HARIF</span>
|
||
</div>
|
||
<span className="text-xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
|
||
</div>
|
||
</Link>
|
||
|
||
{/* LOGIN / SIGN UP */}
|
||
<div className="flex items-center gap-1 shrink-0">
|
||
<button
|
||
onClick={onLoginClick}
|
||
className="bg-brand-primary text-white px-3 h-8 text-[11px] font-bold uppercase"
|
||
>
|
||
LOGIN
|
||
</button>
|
||
<button
|
||
onClick={onRegisterClick}
|
||
className="bg-brand-primary text-white px-3 h-8 text-[11px] font-bold uppercase"
|
||
>
|
||
SIGN UP
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* ===== DESKTOP: Main header bar ===== */}
|
||
<div className="hidden md:flex items-center px-0 bg-brand-bg h-[60px]">
|
||
<Link href="/" className="flex items-center shrink-0">
|
||
<div className="flex items-center bg-brand-surface h-[60px] px-4 w-[280px] shrink-0 border-r border-white/5">
|
||
<div className="bg-brand-accent px-3 py-1 -skew-x-12 flex items-center h-[34px]">
|
||
<span className="text-2xl font-black text-white italic tracking-tighter skew-x-12 inline-block leading-none">HARIF</span>
|
||
</div>
|
||
<span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
|
||
</div>
|
||
</Link>
|
||
<div className="flex items-center flex-1 justify-end px-4 h-full gap-0 bg-brand-surface">
|
||
<Link
|
||
href="/"
|
||
className={cn(
|
||
"flex items-center justify-center h-[60px] w-[50px] shrink-0 transition-colors",
|
||
pathname === "/"
|
||
? "bg-brand-primary hover:bg-brand-primary-hover"
|
||
: "text-white hover:bg-white/10"
|
||
)}
|
||
>
|
||
<svg viewBox="0 0 24 24" className={cn("size-6", pathname === "/" ? "fill-black" : "fill-white")}><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
|
||
</Link>
|
||
<nav className="flex items-center text-[10.5px] font-bold h-full">
|
||
{allNavItems.slice(0, 5).map((item) => {
|
||
const isActive = pathname === item.href && item.href !== "/"
|
||
return (
|
||
<Link key={item.href} href={item.href}
|
||
className={cn(
|
||
"px-4 flex items-center h-full transition-colors uppercase relative",
|
||
isActive ? "text-white bg-brand-primary" : "text-white hover:bg-white/5"
|
||
)}
|
||
>
|
||
<span>{item.label}</span>
|
||
</Link>
|
||
)
|
||
})}
|
||
</nav>
|
||
<nav className="flex items-center text-[10.5px] font-bold h-full">
|
||
{allNavItems.slice(5).map((item) => {
|
||
const isActive = pathname === item.href
|
||
return (
|
||
<Link key={item.href} href={item.href}
|
||
className={cn(
|
||
"px-4 flex flex-col items-center justify-center h-full transition-colors relative uppercase",
|
||
isActive ? "text-white bg-brand-primary" : "text-white hover:bg-white/5"
|
||
)}
|
||
>
|
||
{item.isNew && (
|
||
<span className="absolute top-3 text-[7px] text-white/70 font-black tracking-tighter leading-none">NEW</span>
|
||
)}
|
||
<span className={cn(item.isNew && "mt-1.5")}>{item.label}</span>
|
||
</Link>
|
||
)
|
||
})}
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
{/* ===== MOBILE: Horizontally scrollable nav tabs ===== */}
|
||
<div className="flex md:hidden overflow-x-auto scrollbar-none bg-brand-surface-light border-t border-white/5">
|
||
<Link
|
||
href="/"
|
||
className={cn(
|
||
"flex-none px-4 h-9 flex items-center transition-colors",
|
||
pathname === "/" ? "bg-brand-primary" : "text-white"
|
||
)}
|
||
>
|
||
<svg viewBox="0 0 24 24" className={cn("size-5", pathname === "/" ? "fill-black" : "fill-white")}><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
|
||
</Link>
|
||
{allNavItems.map((item) => {
|
||
const isActive = pathname === item.href
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
className={cn(
|
||
"relative flex-none px-4 h-9 flex items-center text-[11px] font-bold uppercase whitespace-nowrap transition-colors",
|
||
isActive
|
||
? "text-brand-primary border-b-2 border-brand-primary"
|
||
: "text-white/70 hover:text-white"
|
||
)}
|
||
>
|
||
{item.isNew && (
|
||
<span className="absolute top-1 right-1 text-[7px] text-primary font-black leading-none">NEW</span>
|
||
)}
|
||
{item.label}
|
||
</Link>
|
||
)
|
||
})}
|
||
</div>
|
||
|
||
{/* ===== MOBILE: Sport Category Icons Row ===== */}
|
||
<div className="flex md:hidden overflow-x-auto scrollbar-none bg-brand-surface-light border-t border-white/5 py-2 px-2 gap-4">
|
||
{[
|
||
{ label: "Check Bet", icon: (active: boolean) => <svg viewBox="0 0 24 24" className="size-5 fill-white/80"><path d="M20 4H4c-1.11 0-2 .89-2 2v12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/></svg>, count: 99 },
|
||
{ label: "Live", icon: (active: boolean) => <div className="size-2 bg-brand-live rounded-full animate-pulse" />, count: 1247 },
|
||
{ label: "Football", icon: (active: boolean) => <svg viewBox="0 0 24 24" className="size-5 fill-white/80"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z"/></svg>, count: 95 },
|
||
{ label: "Tennis", icon: (active: boolean) => <svg viewBox="0 0 24 24" className="size-5 fill-white/80"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>, count: 384 },
|
||
{ label: "Basketball", icon: (active: boolean) => <svg viewBox="0 0 24 24" className="size-5 fill-white/80"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6z"/></svg>, count: 173 },
|
||
].map((item, idx) => (
|
||
<div key={idx} className="flex flex-col items-center gap-1 shrink-0 px-2 min-w-[60px] relative">
|
||
<span className="absolute -top-1 right-0 bg-white/20 text-white text-[9px] px-1 rounded-sm font-bold">{item.count}</span>
|
||
<div className="size-10 rounded-full bg-white/5 flex items-center justify-center border border-white/5">
|
||
{typeof item.icon === 'function' ? item.icon(false) : item.icon}
|
||
</div>
|
||
<span className="text-[9px] text-white/60 font-medium uppercase tracking-tighter">{item.label}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* ===== DESKTOP: Secondary sub-header ===== */}
|
||
{pathname !== "/virtual" && pathname !== "/special-games" && (
|
||
<div className="hidden md:flex bg-brand-surface-light border-t border-white/5 h-8 px-3 items-center gap-6 text-[11px]">
|
||
{[
|
||
{ label: "Sport Home", href: "/" },
|
||
{ label: "Live View", href: "/live", forceActive: isLivePage },
|
||
].map((tab) => {
|
||
const isActive = tab.forceActive || pathname === tab.href
|
||
return (
|
||
<Link key={tab.label} href={tab.href}
|
||
className={cn(
|
||
"relative h-full flex items-center text-[10px] font-bold uppercase transition-colors tracking-tight px-1",
|
||
isActive ? "text-brand-primary" : "text-white/60 hover:text-white"
|
||
)}
|
||
>
|
||
{tab.label}
|
||
{isActive && tab.label !== "Sport Home" && (
|
||
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-brand-primary" />
|
||
)}
|
||
</Link>
|
||
)
|
||
})}
|
||
</div>
|
||
)}
|
||
</header>
|
||
|
||
{/* ===== MOBILE Drawer ===== */}
|
||
{drawerOpen && (
|
||
<div className="fixed inset-0 z-[9998] flex md:hidden">
|
||
{/* Backdrop */}
|
||
<div className="absolute inset-0 bg-black/60" onClick={() => setDrawerOpen(false)} />
|
||
{/* Drawer panel */}
|
||
<div className="relative w-72 bg-brand-bg h-full flex flex-col shadow-2xl animate-slide-in-left overflow-y-auto">
|
||
{/* Drawer header */}
|
||
<div className="flex items-center justify-between px-4 py-3 bg-brand-surface border-b border-white/10">
|
||
<div className="flex items-center">
|
||
<div className="bg-brand-accent px-2 py-0.5 -skew-x-12 flex items-center h-[24px]">
|
||
<span className="text-base font-black text-white italic tracking-tighter skew-x-12 leading-none">HARIF</span>
|
||
</div>
|
||
<span className="text-base font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
|
||
</div>
|
||
<button onClick={() => setDrawerOpen(false)} className="text-white/60 hover:text-white text-2xl leading-none">×</button>
|
||
</div>
|
||
{/* Nav links */}
|
||
<nav className="flex-1 py-2">
|
||
{drawerLinks.map((link) => (
|
||
<Link
|
||
key={link.href}
|
||
href={link.href}
|
||
className={cn(
|
||
"flex items-center px-5 py-3 text-[13px] font-semibold border-b border-white/5 transition-colors",
|
||
pathname === link.href ? "text-brand-primary bg-white/5" : "text-white/80 hover:text-white hover:bg-white/5"
|
||
)}
|
||
>
|
||
{link.label}
|
||
</Link>
|
||
))}
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</>
|
||
)
|
||
} |