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,104 +4,79 @@ 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 */} {/* ABOUT */}
<div className="mx-auto max-w-5xl px-6"> <div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-20 text-center md:text-left justify-items-center md:justify-items-start"> <h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">ABOUT</h3>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
{/* ABOUT */} <li><Link href="/about" className="hover:text-primary transition-colors">About us</Link></li>
<div> <li><Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link></li>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest"> <li><Link href="/responsible-gaming" className="hover:text-primary transition-colors">Responsible Gaming</Link></li>
ABOUT <li><Link href="/contact" className="hover:text-primary transition-colors">Contact us</Link></li>
</h3> </ul>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> </div>
<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="/responsible-gaming" className="hover:text-primary transition-colors">Responsible Gaming</Link></li>
<li><Link href="/contact" className="hover:text-primary transition-colors">Contact us</Link></li>
</ul>
</div>
{/* 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 <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
</h3> <li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <li><Link href="/faq" className="hover:text-primary transition-colors">FAQ</Link></li>
<li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li> <li><Link href="/rules" className="hover:text-primary transition-colors">Betting Rules</Link></li>
<li><Link href="/faq" className="hover:text-primary transition-colors">FAQ</Link></li> <li><Link href="/info" className="hover:text-primary transition-colors">Betting Information</Link></li>
<li><Link href="/rules" className="hover:text-primary transition-colors">Betting Rules</Link></li> </ul>
<li><Link href="/info" className="hover:text-primary transition-colors">Betting Information</Link></li> </div>
</ul>
</div>
{/* 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 <ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight">
</h3> <li><Link href="/live" className="hover:text-primary transition-colors text-blue-400">Live betting</Link></li>
<ul className="space-y-2 text-[11px] text-white/60 font-medium tracking-tight"> <li><Link href="/football" className="hover:text-primary transition-colors">Football</Link></li>
<li><Link href="/live" className="hover:text-primary transition-colors">Live betting</Link></li> <li><Link href="/basketball" className="hover:text-primary transition-colors">Basketball</Link></li>
<li><Link href="/football" className="hover:text-primary transition-colors">Football</Link></li> <li><Link href="/tennis" className="hover:text-primary transition-colors">Tennis</Link></li>
<li><Link href="/basketball" className="hover:text-primary transition-colors">Basketball</Link></li> <li><Link href="/volleyball" className="hover:text-primary transition-colors">Volleyball</Link></li>
<li><Link href="/tennis" className="hover:text-primary transition-colors">Tennis</Link></li> </ul>
<li><Link href="/volleyball" className="hover:text-primary transition-colors">Volleyball</Link></li> </div>
</ul>
</div>
{/* PLAY NOW */}
<div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">
PLAY NOW
</h3>
<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="/special-games" className="hover:text-primary transition-colors">Special Games</Link></li>
</ul>
</div>
{/* PLAY NOW */}
<div>
<h3 className="text-[12px] font-black uppercase mb-6 tracking-widest">PLAY NOW</h3>
<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="/special-games" className="hover:text-primary transition-colors">Special Games</Link></li>
</ul>
</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 <span className="size-1 bg-white/10 rounded-full" />
</Link> <Link href="/complaints" className="hover:text-primary uppercase transition-colors">Complaints</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="/deposits" className="hover:text-primary uppercase transition-colors">Deposits and Withdrawals</Link>
Complaints
</Link>
<span className="size-1 bg-white/10 rounded-full" />
<Link href="/deposits" className="hover:text-primary uppercase transition-colors">
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 ? ( <span className="text-[11px]"></span>
<img src={league.logo} alt="" className="size-full object-contain" />
) : (
<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,29 +197,102 @@ 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) => {
<button const isExpanded = expandedSport === sport.id
key={sport.id} const leagues = leaguesBySportId[sport.sport_id] ?? []
onClick={() => setActiveSport(sport.id)} const loading = loadingSportId === sport.sport_id
className={cn( const countries = getCountriesForSport(sport.sport_id)
"w-full flex items-center justify-between px-3 py-2 text-left transition-colors border-b border-border/10 h-9",
activeSport === sport.id return (
? "bg-brand-surface text-white" <div key={sport.id} className="border-b border-border/10">
: "text-white/70 hover:bg-brand-surface hover:text-white" {/* Sport row: click only expands/collapses to show countries (no navigation) */}
)} <button
> type="button"
<div className="flex items-center gap-3"> onClick={() => setExpandedSport(isExpanded ? null : sport.id)}
<span className="text-[12px] opacity-80 shrink-0">{sport.icon}</span> className={cn(
<span className="text-[10.5px] font-bold tracking-tight">{sport.name}</span> "w-full flex items-center gap-1 py-2 pr-2 pl-1.5 text-left transition-colors h-9",
isExpanded ? "bg-brand-surface text-brand-primary" : "text-white/80 hover:bg-brand-surface hover:text-white"
)}
>
{isExpanded ? <ChevronUp className="size-3.5 shrink-0 text-current" /> : <ChevronDown className="size-3.5 shrink-0 text-current" />}
<div className="flex items-center gap-2 min-w-0 flex-1">
<span className="text-[12px] shrink-0">{sport.icon}</span>
<span className="text-[10.5px] font-bold truncate">{sport.name}</span>
</div>
{leagues.length > 0 && (
<span className="text-[9px] font-bold text-white/40 shrink-0">{leagues.length}</span>
)}
</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 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>
</button>
))}
</div> </div>
{/* Bet Services */} {/* Bet Services */}