layout components

This commit is contained in:
brooktewabe 2026-03-02 19:10:36 +03:00
parent 0354a182f3
commit 1a1361ee7f
5 changed files with 283 additions and 146 deletions

View File

@ -9,7 +9,7 @@ export type GameCategory =
| "favourite" | "favourite"
| "recently-played" | "recently-played"
| "most-popular" | "most-popular"
| "fortune-special" | "harif-special"
| "for-you" | "for-you"
| "slots" | "slots"
| "crash-games" | "crash-games"
@ -30,7 +30,7 @@ const categories = [
{ id: "favourite", name: "Favourite", icon: Heart }, { id: "favourite", name: "Favourite", icon: Heart },
{ id: "recently-played", name: "Recently Played", icon: Clock }, { id: "recently-played", name: "Recently Played", icon: Clock },
{ id: "most-popular", name: "Most Popular", icon: Star }, { id: "most-popular", name: "Most Popular", icon: Star },
{ id: "fortune-special", name: "Fortune Special", icon: Star }, { id: "harif-special", name: "Harif Special", icon: Zap },
{ id: "for-you", name: "For You", icon: Star }, { id: "for-you", name: "For You", icon: Star },
{ id: "slots", name: "Slots", icon: Star }, { id: "slots", name: "Slots", icon: Star },
{ id: "crash-games", name: "Crash Games", icon: Star }, { id: "crash-games", name: "Crash Games", icon: Star },

View File

@ -14,15 +14,15 @@ function Logo() {
<div key={i} className="w-[5px] h-[38px] bg-[#cc2222] -skew-x-12" /> <div key={i} className="w-[5px] h-[38px] bg-[#cc2222] -skew-x-12" />
))} ))}
</div> </div>
{/* FORTUNE box */} {/* HARIF box */}
<div className="bg-brand-accent px-3 py-1 -skew-x-12 flex items-center h-[38px]"> <div className="bg-brand-accent px-3 py-1 -skew-x-12 flex items-center h-[38px]">
<span className="text-2xl font-black text-white italic tracking-tighter skew-x-12 inline-block leading-none"> <span className="text-2xl font-black text-white italic tracking-tighter skew-x-12 inline-block leading-none">
FORTUNE HARIF
</span> </span>
</div> </div>
{/* SPORT text */} {/* SPORT text */}
<span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none"> <span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">
BETS SPORT
</span> </span>
</div> </div>
) )

View File

@ -4,17 +4,11 @@ import Link from "next/link"
export function SiteFooter() { export function SiteFooter() {
return ( return (
<footer className="bg-brand-surface text-white pt-16"> <footer className="bg-brand-surface text-white pt-12">
<div className="container mx-auto px-6 grid grid-cols-1 md:grid-cols-4 gap-12 text-center md:text-left">
{/* Centered Columns */}
<div className="mx-auto max-w-5xl px-6">
<div className="grid grid-cols-1 md:grid-cols-4 gap-20 text-center md:text-left justify-items-center md:justify-items-start">
{/* ABOUT */} {/* ABOUT */}
<div> <div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest"> <h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">ABOUT</h3>
ABOUT
</h3>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
<li><Link href="/about" className="hover:text-primary transition-colors">About us</Link></li> <li><Link href="/about" className="hover:text-primary transition-colors">About us</Link></li>
<li><Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link></li> <li><Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link></li>
@ -25,9 +19,7 @@ export function SiteFooter() {
{/* INFORMATION */} {/* INFORMATION */}
<div> <div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest"> <h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">INFORMATION</h3>
INFORMATION
</h3>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
<li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li> <li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li>
<li><Link href="/faq" className="hover:text-primary transition-colors">FAQ</Link></li> <li><Link href="/faq" className="hover:text-primary transition-colors">FAQ</Link></li>
@ -38,11 +30,9 @@ export function SiteFooter() {
{/* SPORTS */} {/* SPORTS */}
<div> <div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest"> <h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">SPORTS</h3>
SPORTS
</h3>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
<li><Link href="/live" className="hover:text-primary transition-colors">Live betting</Link></li> <li><Link href="/live" className="hover:text-primary transition-colors text-blue-400">Live betting</Link></li>
<li><Link href="/football" className="hover:text-primary transition-colors">Football</Link></li> <li><Link href="/football" className="hover:text-primary transition-colors">Football</Link></li>
<li><Link href="/basketball" className="hover:text-primary transition-colors">Basketball</Link></li> <li><Link href="/basketball" className="hover:text-primary transition-colors">Basketball</Link></li>
<li><Link href="/tennis" className="hover:text-primary transition-colors">Tennis</Link></li> <li><Link href="/tennis" className="hover:text-primary transition-colors">Tennis</Link></li>
@ -52,56 +42,41 @@ export function SiteFooter() {
{/* PLAY NOW */} {/* PLAY NOW */}
<div> <div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest"> <h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">PLAY NOW</h3>
PLAY NOW
</h3>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
<li><Link href="/virtual" className="hover:text-primary transition-colors">Virtual</Link></li> <li><Link href="/virtual" className="hover:text-primary transition-colors">Virtual</Link></li>
<li><Link href="/special-games" className="hover:text-primary transition-colors">Special Games</Link></li> <li><Link href="/special-games" className="hover:text-primary transition-colors">Special Games</Link></li>
</ul> </ul>
</div> </div>
</div>
</div> </div>
{/* Logo Section */} {/* Logo Section */}
<div className="flex flex-col items-center justify-center py-16 border-t border-white/5 mt-16 bg-brand-surface-light"> <div className="flex flex-col items-center justify-center py-16 border-t border-white/5 mt-12 bg-brand-surface-light">
<div className="flex items-center bg-brand-surface px-5 py-2"> <div className="flex items-center bg-brand-surface px-5 py-2">
<div className="bg-brand-accent px-3 py-1 -skew-x-12"> <div className="bg-brand-accent px-3 py-1 -skew-x-12">
<span className="text-3xl font-black text-white italic tracking-tighter skew-x-12 inline-block"> <span className="text-3xl font-black text-white italic tracking-tighter skew-x-12 inline-block">HARIF</span>
FORTUNE
</span>
</div> </div>
<span className="text-3xl font-black text-brand-primary italic tracking-tighter ml-1"> <span className="text-3xl font-black text-brand-primary italic tracking-tighter ml-1">SPORT</span>
BETS
</span>
</div> </div>
{/* Footer Links */} {/* Footer Links */}
<div className="flex flex-wrap items-center justify-center gap-6 mt-12 text-[11px] font-bold tracking-tight text-white/80"> <div className="flex flex-wrap items-center justify-center gap-6 mt-12 text-[11px] font-bold tracking-tight text-white/80">
<Link href="/affiliates" className="hover:text-primary uppercase transition-colors"> <Link href="/affiliates" className="hover:text-primary uppercase transition-colors">Affiliates</Link>
Affiliates
</Link>
<span className="size-1 bg-white/10 rounded-full" /> <span className="size-1 bg-white/10 rounded-full" />
<Link href="/complaints" className="hover:text-primary uppercase transition-colors"> <Link href="/complaints" className="hover:text-primary uppercase transition-colors">Complaints</Link>
Complaints
</Link>
<span className="size-1 bg-white/10 rounded-full" /> <span className="size-1 bg-white/10 rounded-full" />
<Link href="/deposits" className="hover:text-primary uppercase transition-colors"> <Link href="/deposits" className="hover:text-primary uppercase transition-colors">Deposits and Withdrawals</Link>
Deposits and Withdrawals
</Link>
</div> </div>
</div> </div>
{/* Cookie Text */} {/* Cookie Text */}
<div className="bg-brand-bg py-10 px-6 text-center"> <div className="bg-brand-bg py-10 px-6 text-center">
<div className="mx-auto max-w-5xl"> <div className="container mx-auto max-w-5xl">
<p className="text-[10px] text-white/40 leading-relaxed font-medium uppercase tracking-tight"> <p className="text-[10px] text-white/40 leading-relaxed font-medium uppercase tracking-tight">
By accessing, or continuing to use or browse this site, you consent to our use of certain cookies to improve your experience with us. We only use cookies that will enhance your experience and will not interfere with your privacy. Please look at our Cookie Policy for further informations on our use of the cookie and how you can disable it or manage it if you so choose. By accessing, or continuing to use or browse this site, you consent to our use of certain cookies to improve your experience with us. We only use cookies that will enhance your experience and will not interfere with your privacy. Please look at our Cookie Policy for further informations on our use of the cookie and how you can disable it or manage it if you so choose.
</p> </p>
</div> </div>
</div> </div>
</footer> </footer>
) )
} }

View File

@ -17,7 +17,7 @@ const allNavItems = [
{ href: "/poker", label: "POKER", isNew: true }, { href: "/poker", label: "POKER", isNew: true },
{ href: "/race", label: "RACE", isNew: true }, { href: "/race", label: "RACE", isNew: true },
{ href: "/promo", label: "PROMO" }, { href: "/promo", label: "PROMO" },
// { href: "/aviator", label: "AVIATOR" }, { href: "/aviator", label: "AVIATOR" },
] ]
const drawerLinks = [ const drawerLinks = [
@ -118,9 +118,9 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<Link href="/" className="flex-1 flex items-center justify-center"> <Link href="/" className="flex-1 flex items-center justify-center">
<div className="flex items-center"> <div className="flex items-center">
<div className="bg-brand-accent px-2 py-0.5 -skew-x-12 flex items-center h-[28px]"> <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">FORTUNE</span> <span className="text-xl font-black text-white italic tracking-tighter skew-x-12 leading-none">HARIF</span>
</div> </div>
<span className="text-xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">BETS</span> <span className="text-xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
</div> </div>
</Link> </Link>
@ -146,9 +146,9 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<Link href="/" className="flex items-center shrink-0"> <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="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]"> <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">FORTUNE</span> <span className="text-2xl font-black text-white italic tracking-tighter skew-x-12 inline-block leading-none">HARIF</span>
</div> </div>
<span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">BETS</span> <span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
</div> </div>
</Link> </Link>
<div className="flex items-center flex-1 justify-end px-4 h-full gap-0 bg-brand-surface"> <div className="flex items-center flex-1 justify-end px-4 h-full gap-0 bg-brand-surface">
@ -288,9 +288,9 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<div className="flex items-center justify-between px-4 py-3 bg-brand-surface border-b border-white/10"> <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="flex items-center">
<div className="bg-brand-accent px-2 py-0.5 -skew-x-12 flex items-center h-[24px]"> <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">FORTUNE</span> <span className="text-base font-black text-white italic tracking-tighter skew-x-12 leading-none">HARIF</span>
</div> </div>
<span className="text-base font-black text-brand-primary italic tracking-tighter ml-1 leading-none">BETS</span> <span className="text-base font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
</div> </div>
<button onClick={() => setDrawerOpen(false)} className="text-white/60 hover:text-white text-2xl leading-none">×</button> <button onClick={() => setDrawerOpen(false)} className="text-white/60 hover:text-white text-2xl leading-none">×</button>
</div> </div>

View File

@ -1,13 +1,32 @@
"use client" "use client"
import { useState } from "react" import { useState, useEffect, useMemo } from "react"
import Link from "next/link" import Link from "next/link"
import { popularLeagues } from "@/lib/mock-data" import { useSearchParams } from "next/navigation"
import { TOP_LEAGUES, fetchLeagues } from "@/lib/store/betting-api"
import { useBettingStore } from "@/lib/store/betting-store"
import type { ApiLeague } from "@/lib/store/betting-types"
import { SportEnum, type QuickFilterKey } from "@/lib/store/betting-types"
import { getCountryName } from "@/lib/countries"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { ChevronsLeft } from "lucide-react" import { ChevronsLeft, ChevronDown, ChevronUp, Plus } from "lucide-react"
/** Sidebar sports: slug for URL, sport_id for /leagues?sport_id= (order and list from design) */
const SIDEBAR_SPORTS = [
{ id: "football", sport_id: SportEnum.SOCCER, name: "Football", icon: "⚽" },
{ id: "basketball", sport_id: SportEnum.BASKETBALL, name: "Basketball", icon: "🏀" },
{ id: "american-football", sport_id: SportEnum.AMERICAN_FOOTBALL, name: "American Football", icon: "🏈" },
{ id: "baseball", sport_id: SportEnum.BASEBALL, name: "Baseball", icon: "⚾" },
{ id: "cricket", sport_id: SportEnum.CRICKET, name: "Cricket", icon: "🏏" },
{ id: "futsal", sport_id: SportEnum.FUTSAL, name: "Futsal", icon: "⚽" },
{ id: "darts", sport_id: SportEnum.DARTS, name: "Darts", icon: "🎯" },
{ id: "ice-hockey", sport_id: SportEnum.ICE_HOCKEY, name: "Ice Hockey", icon: "🏒" },
{ id: "rugby-union", sport_id: SportEnum.RUGBY_UNION, name: "Rugby", icon: "🏉" },
{ id: "rugby-league", sport_id: SportEnum.RUGBY_LEAGUE, name: "Rugby League", icon: "🏉" },
{ id: "volleyball", sport_id: SportEnum.VOLLEYBALL, name: "Volleyball", icon: "🏐" },
]
/** Soccer ball icon - outline style for white/green theme */
function SoccerBallIcon({ className }: { className?: string }) { function SoccerBallIcon({ className }: { className?: string }) {
return ( return (
<svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"> <svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
@ -18,23 +37,106 @@ function SoccerBallIcon({ className }: { className?: string }) {
) )
} }
const sportCategories = [ const QUICK_FILTER_OPTIONS: { label: string; key: QuickFilterKey }[] = [
{ id: "football", name: "Football", icon: "⚽", count: 1412 }, { label: "All", key: "all" },
{ id: "tennis", name: "Tennis", icon: "🎾", count: 67 }, { label: "Today", key: "today" },
{ id: "basketball", name: "Basketball", icon: "🏀", count: 255 }, { label: "3h", key: "3h" },
{ id: "ice-hockey", name: "Ice Hockey", icon: "🏒", count: 238 }, { label: "6h", key: "6h" },
{ id: "mma", name: "MMA", icon: "🥊", count: 51 }, { label: "9h", key: "9h" },
{ id: "handball", name: "Handball", icon: "🤾", count: 92 }, { label: "12h", key: "12h" },
{ id: "darts", name: "Darts", icon: "🎯", count: 25 },
{ id: "snooker", name: "Snooker", icon: "🎱", count: 3 },
{ id: "cricket", name: "Cricket", icon: "🏏", count: 42 },
{ id: "dota2", name: "Dota 2", icon: "🎮", count: 2 },
{ id: "rugby", name: "Rugby", icon: "🏉", count: 41 },
{ id: "volleyball", name: "Volleyball", icon: "🏐", count: 69 },
] ]
function QuickFilterSection() {
const quickFilter = useBettingStore((s) => s.quickFilter)
const setQuickFilter = useBettingStore((s) => s.setQuickFilter)
return (
<div className="bg-brand-surface p-3 border-b border-border/30">
<span className="text-brand-primary text-[10.5px] uppercase font-black block mb-2 tracking-tight">Quick Filter</span>
<div className="grid grid-cols-6 gap-px">
{QUICK_FILTER_OPTIONS.map(({ label, key }) => (
<button
key={key}
type="button"
onClick={() => setQuickFilter(key)}
className={cn(
"text-[10px] py-1.5 font-bold transition-colors",
quickFilter === key ? "bg-brand-surface-light text-white" : "bg-brand-surface text-white/50 hover:text-white"
)}
>
{label}
</button>
))}
</div>
</div>
)
}
export function SportsSidebar() { export function SportsSidebar() {
const [activeSport, setActiveSport] = useState("football") const searchParams = useSearchParams()
const sportFromUrl = searchParams.get("sport") ?? "football"
const leagueFromUrl = searchParams.get("league")
const [expandedSport, setExpandedSport] = useState<string | null>(sportFromUrl)
const [expandedCountries, setExpandedCountries] = useState<Set<string>>(new Set())
const [leaguesBySportId, setLeaguesBySportId] = useState<Record<number, ApiLeague[]>>({})
const [loadingSportId, setLoadingSportId] = useState<number | null>(null)
useEffect(() => {
setExpandedSport((prev) => (prev ?? sportFromUrl) || sportFromUrl)
}, [sportFromUrl])
const currentSport = SIDEBAR_SPORTS.find((s) => s.id === sportFromUrl)
const sportId = currentSport?.sport_id ?? SportEnum.SOCCER
useEffect(() => {
if (!expandedSport) return
const sport = SIDEBAR_SPORTS.find((s) => s.id === expandedSport)
if (!sport || sport.sport_id in leaguesBySportId) return
let cancelled = false
setLoadingSportId(sport.sport_id)
fetchLeagues(sport.sport_id)
.then((res) => {
if (!cancelled) setLeaguesBySportId((prev) => ({ ...prev, [sport.sport_id]: res.data ?? [] }))
})
.catch(() => {
if (!cancelled) setLeaguesBySportId((prev) => ({ ...prev, [sport.sport_id]: [] }))
})
.finally(() => {
if (!cancelled) setLoadingSportId(null)
})
return () => {
cancelled = true
}
}, [expandedSport, leaguesBySportId])
const toggleCountry = (cc: string) => {
setExpandedCountries((prev) => {
const next = new Set(prev)
if (next.has(cc)) next.delete(cc)
else next.add(cc)
return next
})
}
const getCountriesForSport = (sportIdNum: number) => {
const leagues = leaguesBySportId[sportIdNum] ?? []
const ccSet = new Set<string>()
leagues.forEach((l) => ccSet.add((l.cc || "").trim().toLowerCase() || "__intl__"))
return Array.from(ccSet)
.map((cc) => ({
cc: cc === "__intl__" ? "" : cc,
name: cc === "__intl__" ? "International" : getCountryName(cc),
}))
.sort((a, b) => a.name.localeCompare(b.name))
}
const getLeaguesForCountry = (sportIdNum: number, countryCc: string) => {
const leagues = leaguesBySportId[sportIdNum] ?? []
const cc = countryCc.toLowerCase()
return leagues
.filter((l) => ((l.cc || "").trim().toLowerCase() || "") === cc)
.sort((a, b) => a.name.localeCompare(b.name))
}
return ( return (
<aside className="hidden h-full w-[280px] shrink-0 bg-brand-surface-light lg:block overflow-y-auto border-r border-border/40 scrollbar-hide"> <aside className="hidden h-full w-[280px] shrink-0 bg-brand-surface-light lg:block overflow-y-auto border-r border-border/40 scrollbar-hide">
@ -51,21 +153,18 @@ export function SportsSidebar() {
Top Leagues Top Leagues
</div> </div>
{/* Popular Leagues */} {/* Top Leagues */}
<div className="flex flex-col"> <div className="flex flex-col">
{popularLeagues.map((league) => ( {TOP_LEAGUES.map((league) => (
<Link <Link
key={league.id} key={league.id}
href={`/?league=${league.id}`} href={`/?sport=${sportFromUrl}&league=${league.id}`}
scroll={false}
className="w-full flex items-center justify-between px-3 py-2 text-left text-white/90 hover:bg-brand-surface transition-colors border-b border-border/10 group h-9" className="w-full flex items-center justify-between px-3 py-2 text-left text-white/90 hover:bg-brand-surface transition-colors border-b border-border/10 group h-9"
> >
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center gap-2 min-w-0">
<div className="size-5 shrink-0 overflow-hidden rounded-sm flex items-center justify-center bg-white/5 border border-white/10 group-hover:border-white/20 transition-colors"> <div className="size-5 shrink-0 overflow-hidden rounded-sm flex items-center justify-center bg-white/5 border border-white/10 group-hover:border-white/20 transition-colors">
{league.logo ? (
<img src={league.logo} alt="" className="size-full object-contain" />
) : (
<span className="text-[11px]"></span> <span className="text-[11px]"></span>
)}
</div> </div>
<span className="text-white/50 text-[8px] font-bold select-none"></span> <span className="text-white/50 text-[8px] font-bold select-none"></span>
<span className="text-[10.5px] font-bold leading-tight truncate max-w-[140px]">{league.name}</span> <span className="text-[10.5px] font-bold leading-tight truncate max-w-[140px]">{league.name}</span>
@ -83,18 +182,8 @@ export function SportsSidebar() {
</Link> </Link>
</Button> </Button>
{/* Quick Filter Section */} {/* Quick Filter Section: passes first_start_time (RFC3339) to events API */}
<div className="bg-brand-surface p-3 border-b border-border/30"> <QuickFilterSection />
<span className="text-brand-primary text-[10.5px] uppercase font-black block mb-2 tracking-tight">Quick Filter</span>
<div className="grid grid-cols-6 gap-[1px]">
{["All", "Today", "3h", "6h", "9h", "12h"].map((t) => (
<button key={t} className={cn(
"text-[10px] py-1.5 font-bold transition-colors",
t === "All" ? "bg-brand-surface-light text-white" : "bg-brand-surface text-white/50 hover:text-white"
)}>{t}</button>
))}
</div>
</div>
{/* Search Event Section */} {/* Search Event Section */}
<div className="bg-brand-surface p-3 border-b border-border/40"> <div className="bg-brand-surface p-3 border-b border-border/40">
@ -108,30 +197,103 @@ export function SportsSidebar() {
</div> </div>
</div> </div>
{/* Sport categories */} {/* Nested: Sport → Countries → Leagues (mapped to sport_id & leagues API cc) */}
<div className="divide-y divide-border/10 bg-brand-surface-light"> <div className="divide-y divide-border/10 bg-brand-surface-light">
{sportCategories.map((sport) => ( {SIDEBAR_SPORTS.map((sport) => {
const isExpanded = expandedSport === sport.id
const leagues = leaguesBySportId[sport.sport_id] ?? []
const loading = loadingSportId === sport.sport_id
const countries = getCountriesForSport(sport.sport_id)
return (
<div key={sport.id} className="border-b border-border/10">
{/* Sport row: click only expands/collapses to show countries (no navigation) */}
<button <button
key={sport.id} type="button"
onClick={() => setActiveSport(sport.id)} onClick={() => setExpandedSport(isExpanded ? null : sport.id)}
className={cn( className={cn(
"w-full flex items-center justify-between px-3 py-2 text-left transition-colors border-b border-border/10 h-9", "w-full flex items-center gap-1 py-2 pr-2 pl-1.5 text-left transition-colors h-9",
activeSport === sport.id isExpanded ? "bg-brand-surface text-brand-primary" : "text-white/80 hover:bg-brand-surface hover:text-white"
? "bg-brand-surface text-white"
: "text-white/70 hover:bg-brand-surface hover:text-white"
)} )}
> >
<div className="flex items-center gap-3"> {isExpanded ? <ChevronUp className="size-3.5 shrink-0 text-current" /> : <ChevronDown className="size-3.5 shrink-0 text-current" />}
<span className="text-[12px] opacity-80 shrink-0">{sport.icon}</span> <div className="flex items-center gap-2 min-w-0 flex-1">
<span className="text-[10.5px] font-bold tracking-tight">{sport.name}</span> <span className="text-[12px] shrink-0">{sport.icon}</span>
</div> <span className="text-[10.5px] font-bold truncate">{sport.name}</span>
<div className="flex items-center gap-2">
<span className="text-[10px] font-bold text-white/40">{sport.count}</span>
<SoccerBallIcon className="size-3.5 text-white/30 shrink-0" />
</div> </div>
{leagues.length > 0 && (
<span className="text-[9px] font-bold text-white/40 shrink-0">{leagues.length}</span>
)}
</button> </button>
{/* Countries (nested under sport) */}
{isExpanded && (
<div className="bg-brand-surface-light/80 pl-4">
{loading ? (
<div className="py-2 text-[10px] text-white/50">Loading</div>
) : (
countries.map(({ cc, name }) => {
const countryExpanded = expandedCountries.has(cc || "__intl__")
const countryKey = cc || "__intl__"
const leaguesInCountry = getLeaguesForCountry(sport.sport_id, cc)
return (
<div key={countryKey} className="border-b border-border/5">
<button
type="button"
onClick={() => toggleCountry(countryKey)}
className={cn(
"w-full flex items-center justify-between gap-2 py-1.5 pr-2 text-left text-[10.5px] font-bold transition-colors",
countryExpanded ? "text-brand-primary" : "text-white/80 hover:text-white"
)}
>
<div className="flex items-center gap-2 min-w-0">
{cc ? (
<img
src={`https://flagcdn.com/w20/${cc}.png`}
alt=""
width={20}
height={14}
className="shrink-0 rounded-sm object-cover w-5 h-[14px]"
/>
) : (
<span className="size-5 shrink-0 flex items-center justify-center text-[10px] text-white/50"></span>
)}
<span className="truncate">{name}</span>
</div>
{countryExpanded ? <ChevronUp className="size-3 shrink-0" /> : <ChevronDown className="size-3 shrink-0" />}
</button>
{/* Leagues (nested under country) */}
{countryExpanded && (
<div className="pl-2 pb-1 max-h-48 overflow-y-auto">
{leaguesInCountry.map((league) => (
<Link
key={league.id}
href={`/?sport=${sport.id}&league=${league.id}`}
scroll={false}
className={cn(
"flex items-center justify-between gap-1 py-1.5 pr-1 text-[10px] font-bold border-b border-border/5 hover:bg-brand-surface/50 transition-colors group",
leagueFromUrl === String(league.id) ? "text-brand-primary" : "text-white/90"
)}
>
<span className="text-white/50 text-[8px] group-hover:text-brand-primary"></span>
<span className="flex-1 truncate">{league.name}</span>
<Plus className="size-3 shrink-0 text-white/40 group-hover:text-brand-primary" />
</Link>
))} ))}
</div> </div>
)}
</div>
)
})
)}
</div>
)}
</div>
)
})}
</div>
{/* Bet Services */} {/* Bet Services */}
<div className="mt-2 text-[11px] font-bold text-brand-primary px-3 py-2 uppercase border-y border-border/20 bg-brand-surface"> <div className="mt-2 text-[11px] font-bold text-brand-primary px-3 py-2 uppercase border-y border-border/20 bg-brand-surface">