feat: add hero banner, live events list, and sports navigation components

- Implemented HeroBanner component for image carousel with navigation arrows and indicators.
- Created LiveEventsList component to display live events with odds and match details.
- Added SportsNav component for sport category navigation with icons.
- Introduced TopMatches component to showcase highlighted matches with odds.
- Updated InPlayHeader and QuickFilterBar for improved UI and functionality.
- Enhanced ReloadTicket and SearchEvent components for better user experience.
- Refactored SportsSidebar to include popular leagues and quick filter options.
- Added new sport-home layout to integrate various betting components.
This commit is contained in:
brooktewabe 2026-02-20 12:22:04 +03:00
parent 6376713398
commit 612bb9386b
14 changed files with 1194 additions and 246 deletions

View File

@ -1,25 +1,29 @@
import { Separator } from "@/components/ui/separator"
import { BarChart2, PrinterIcon, Trophy } from "lucide-react"
const services = ["Live Score", "Results", "Print Odds"]
const services = [
{ label: "Live Score", icon: BarChart2 },
{ label: "Results", icon: Trophy },
{ label: "Print Odds", icon: PrinterIcon },
]
export function BetServices() {
return (
<div className="flex items-center gap-3 rounded-md border bg-card/60 px-3 py-2 text-[11px]">
<span className="font-medium uppercase tracking-wide text-muted-foreground">
Bet Services
<div className="flex items-center gap-0 bg-secondary rounded border border-border overflow-hidden text-[11px]">
<span className="px-3 py-2 font-bold uppercase text-muted-foreground text-[10px] tracking-wider border-r border-border">
Services
</span>
<Separator orientation="vertical" className="h-4" />
<div className="flex flex-wrap gap-2">
{services.map((service) => (
{services.map((service, i) => {
const Icon = service.icon
return (
<button
key={service}
className="text-[11px] text-primary underline-offset-2 hover:underline"
key={service.label}
className={`flex items-center gap-1.5 px-3 py-2 text-muted-foreground hover:text-primary hover:bg-muted transition-colors ${i < services.length - 1 ? "border-r border-border" : ""}`}
>
{service}
<Icon className="size-3" />
{service.label}
</button>
))}
</div>
)
})}
</div>
)
}

View File

@ -1,64 +1,187 @@
import { useBetslipStore } from "@/lib/store/betslip-store";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
"use client"
import { useState } from "react"
import { useBetslipStore } from "@/lib/store/betslip-store"
import { X, ChevronDown, Trash2 } from "lucide-react"
import { cn } from "@/lib/utils"
const quickStakes = [5, 10, 20, 50, 100, 200]
export function Betslip() {
const { bets, removeBet, clearBets } = useBetslipStore();
const { bets, removeBet, clearBets, updateStake, getPotentialWin, getTotalOdds } = useBetslipStore()
const [activeTab, setActiveTab] = useState<"single" | "accumulator">("single")
const [globalStake, setGlobalStake] = useState("10")
const potentialWin = getPotentialWin()
const totalOdds = getTotalOdds()
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0">
<CardTitle className="text-sm font-semibold">
Betslip {bets.length}
</CardTitle>
<div className="bg-card rounded border border-border overflow-hidden">
{/* Header */}
<div className="bg-primary px-3 py-2 flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-[11px] font-bold text-primary-foreground uppercase">Betslip</span>
{bets.length > 0 && (
<span className="bg-primary-foreground text-primary text-[10px] font-bold px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
{bets.length}
</span>
)}
</div>
{bets.length > 0 && (
<button
onClick={clearBets}
className="text-xs text-muted-foreground hover:underline"
className="text-primary-foreground/70 hover:text-primary-foreground transition-colors"
>
Clear all
<Trash2 className="size-3.5" />
</button>
)}
</CardHeader>
<CardContent className="space-y-3 text-xs">
</div>
{/* Tabs */}
{bets.length > 1 && (
<div className="flex border-b border-border">
{(["single", "accumulator"] as const).map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={cn(
"flex-1 py-1.5 text-[10px] font-semibold uppercase transition-colors",
activeTab === tab
? "bg-muted text-foreground border-b-2 border-primary"
: "text-muted-foreground hover:text-foreground"
)}
>
{tab}
</button>
))}
</div>
)}
{/* Content */}
<div className="p-2 space-y-2">
{bets.length === 0 ? (
<p className="text-muted-foreground">
No bet has been selected. To select a bet, please click on the
respective odds.
<div className="py-6 text-center">
<div className="text-2xl mb-2">🎯</div>
<p className="text-[11px] text-muted-foreground leading-relaxed">
No bets selected. Click on odds to add selections.
</p>
</div>
) : (
<>
{/* Bet items */}
<div className="space-y-2">
{bets.map((bet) => (
<div
key={bet.id}
className="rounded border bg-card/40 p-2 text-xs"
>
<div className="flex items-center justify-between">
<div>
<div className="font-medium">{bet.event}</div>
<div className="text-[10px] text-muted-foreground">
{bet.market} {bet.selection}
<div key={bet.id} className="bg-secondary/50 rounded border border-border/50 p-2">
<div className="flex items-start justify-between gap-2 mb-2">
<div className="flex-1 min-w-0">
<div className="text-[11px] font-semibold text-foreground truncate">{bet.event}</div>
<div className="text-[10px] text-muted-foreground truncate">{bet.league}</div>
<div className="text-[10px] text-primary font-medium mt-0.5">
{bet.market}: <span className="text-foreground">{bet.selection}</span>
</div>
</div>
<div className="text-right">
<div className="font-semibold">{bet.odds.toFixed(2)}</div>
<div className="flex items-center gap-1.5 shrink-0">
<span className="text-sm font-bold text-primary">{bet.odds.toFixed(2)}</span>
<button
onClick={() => removeBet(bet.id)}
className="text-[10px] text-destructive hover:underline"
className="text-muted-foreground hover:text-destructive transition-colors"
>
Remove
<X className="size-3.5" />
</button>
</div>
</div>
{/* Stake input for single */}
{(activeTab === "single" || bets.length === 1) && (
<div>
<div className="text-[10px] text-muted-foreground mb-1">Stake (ETB)</div>
<div className="flex gap-1">
<input
type="number"
value={bet.stake ?? 10}
onChange={(e) => updateStake(bet.id, Number(e.target.value))}
className="flex-1 bg-input border border-border rounded px-2 py-1 text-xs text-foreground w-full min-w-0 focus:outline-none focus:border-primary"
min="1"
/>
</div>
<div className="flex gap-1 mt-1 flex-wrap">
{quickStakes.map((s) => (
<button
key={s}
onClick={() => updateStake(bet.id, s)}
className={cn(
"text-[10px] px-1.5 py-0.5 rounded border transition-colors",
(bet.stake ?? 10) === s
? "bg-primary text-primary-foreground border-primary"
: "border-border text-muted-foreground hover:border-primary hover:text-primary"
)}
>
{s}
</button>
))}
<Button className="w-full text-xs" size="sm">
Place bet
</Button>
</div>
{/* Potential win */}
<div className="mt-1.5 flex justify-between text-[10px]">
<span className="text-muted-foreground">Potential win:</span>
<span className="text-primary font-semibold">
{((bet.stake ?? 10) * bet.odds).toFixed(2)} ETB
</span>
</div>
</div>
)}
</CardContent>
</Card>
);
}
</div>
))}
</div>
{/* Accumulator stake section */}
{activeTab === "accumulator" && bets.length > 1 && (
<div className="bg-secondary/50 rounded border border-border/50 p-2 space-y-2">
<div className="flex justify-between text-[11px]">
<span className="text-muted-foreground">Total Odds:</span>
<span className="font-bold text-primary">{totalOdds.toFixed(2)}</span>
</div>
<div>
<div className="text-[10px] text-muted-foreground mb-1">Stake (ETB)</div>
<input
type="number"
value={globalStake}
onChange={(e) => setGlobalStake(e.target.value)}
className="w-full bg-input border border-border rounded px-2 py-1 text-xs text-foreground focus:outline-none focus:border-primary"
min="1"
/>
<div className="flex gap-1 mt-1 flex-wrap">
{quickStakes.map((s) => (
<button
key={s}
onClick={() => setGlobalStake(String(s))}
className={cn(
"text-[10px] px-1.5 py-0.5 rounded border transition-colors",
globalStake === String(s)
? "bg-primary text-primary-foreground border-primary"
: "border-border text-muted-foreground hover:border-primary hover:text-primary"
)}
>
{s}
</button>
))}
</div>
<div className="mt-1.5 flex justify-between text-[10px]">
<span className="text-muted-foreground">Potential win:</span>
<span className="text-primary font-semibold">
{(Number(globalStake) * totalOdds).toFixed(2)} ETB
</span>
</div>
</div>
</div>
)}
{/* Place bet button */}
<button className="w-full bg-primary text-primary-foreground text-[12px] font-bold py-2.5 rounded hover:opacity-90 active:scale-95 transition-all uppercase tracking-wide">
Place Bet
</button>
</>
)}
</div>
</div>
)
}

View File

@ -1,26 +1,50 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
"use client"
import { useState } from "react"
export function CheckYourBet() {
const [betId, setBetId] = useState("")
const [result, setResult] = useState<null | "pending" | "won" | "lost">(null)
const handleCheck = () => {
if (!betId.trim()) return
// Mock result
const results = ["pending", "won", "lost"] as const
setResult(results[Math.floor(Math.random() * results.length)])
}
return (
<Card>
<CardHeader>
<CardTitle className="text-sm">Check your bet</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-xs">
<div className="text-[11px] text-muted-foreground">Your bet ID</div>
<div className="flex gap-2">
<Input
placeholder="Bet ID"
className="h-8 text-xs placeholder:text-[11px]"
<div className="bg-transparent border-t border-border/20 pt-4 pb-2">
<div className="px-1 text-center space-y-3">
<h3 className="text-[12px] font-bold uppercase text-[#ff9800]">Check Your Bet</h3>
<p className="text-[11px] text-white">Your bet ID</p>
<div className="flex gap-1">
<input
type="text"
value={betId}
onChange={(e) => setBetId(e.target.value)}
className="flex-1 bg-[#121212] border border-border/40 px-2 py-2 text-[11px] text-white outline-none focus:border-primary"
onKeyDown={(e) => e.key === "Enter" && handleCheck()}
/>
<Button size="sm" className="text-xs">
Check
</Button>
<button
onClick={handleCheck}
className="bg-[#ff9800] text-black px-2 py-1.5 flex items-center justify-center min-w-[32px] hover:bg-[#ffa726] transition-colors"
>
<svg viewBox="0 0 24 24" className="size-5 fill-current"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
{result && (
<div className={`text-[11px] font-semibold p-2 rounded text-center mt-2 ${
result === "won" ? "bg-primary/20 text-primary" :
result === "lost" ? "bg-destructive/20 text-destructive" :
"bg-secondary text-muted-foreground"
}`}>
{result === "won" && "🎉 Bet Won!"}
{result === "lost" && "❌ Bet Lost"}
{result === "pending" && "⏳ Bet Pending"}
</div>
)}
</div>
</div>
</CardContent>
</Card>
)
}

View File

@ -1,80 +1,310 @@
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { ScrollArea } from "@/components/ui/scroll-area"
"use client"
import { useState, useEffect } from "react"
import { useSearchParams } from "next/navigation"
import { useBetslipStore } from "@/lib/store/betslip-store"
import { mockEvents, popularLeagues, type Event } from "@/lib/mock-data"
import { cn } from "@/lib/utils"
import { ChevronDown, BarChart2, TrendingUp, Plus } from "lucide-react"
const mockEvents = [
{
id: "1",
sport: "Soccer",
name: "Team A vs Team B",
markets: [
{ id: "1x2_home", label: "1", odds: 1.85 },
{ id: "1x2_draw", label: "X", odds: 3.4 },
{ id: "1x2_away", label: "2", odds: 4.1 },
],
},
{
id: "2",
sport: "Basketball",
name: "City Wolves vs Lake Bears",
markets: [
{ id: "spread_home", label: "Home -4.5", odds: 1.9 },
{ id: "spread_away", label: "Away +4.5", odds: 1.9 },
],
},
]
export function EventsList() {
const { addBet } = useBetslipStore()
function OddsButton({ odds, onClick, isSelected }: {
odds: number
onClick: () => void
isSelected: boolean
}) {
return (
<Card className="flex-1">
<CardContent className="px-0 pb-4 pt-3">
<ScrollArea className="h-[360px]">
<div className="space-y-2 px-3 pb-2">
{mockEvents.map((event) => (
<div
key={event.id}
className="rounded-md border bg-card/50 p-2 text-xs"
<button
onClick={onClick}
className={cn(
"flex items-center justify-center py-2 px-0.5 border-r border-border/10 text-[10px] transition-all min-w-0 bg-[#262626] hover:bg-[#333] h-full",
isSelected && "bg-[#ff9800] text-black font-bold border-none"
)}
>
<div className="flex items-center justify-between">
<div>
<div className="font-medium">{event.name}</div>
<div className="text-[11px] text-muted-foreground">
{event.sport}
</div>
</div>
</div>
<div className="mt-2 flex flex-wrap gap-1.5">
{event.markets.map((market) => (
<Button
key={market.id}
size="xs"
className="min-w-[60px] justify-between rounded-sm bg-secondary text-secondary-foreground text-[11px] hover:bg-primary hover:text-primary-foreground"
onClick={() =>
addBet({
id: `${event.id}-${market.id}`,
event: event.name,
market: event.sport,
selection: market.label,
odds: market.odds,
})
}
>
<span>{market.label}</span>
<span className="font-semibold">
{market.odds.toFixed(2)}
</span>
</Button>
))}
</div>
</div>
))}
</div>
</ScrollArea>
</CardContent>
</Card>
<span className={cn("font-bold tracking-tighter", isSelected ? "text-black" : "text-[#ff9800]")}>{odds.toFixed(2)}</span>
</button>
)
}
function EventRow({ event }: { event: Event }) {
const { bets, addBet } = useBetslipStore()
return (
<div className="bg-[#1a1a1a] border-b border-border/20 hover:bg-[#222] transition-colors h-[38px] flex items-center">
{/* Small Icons & ID Column */}
<div className="flex items-center gap-1.5 px-2 w-[80px] shrink-0 border-r border-border/10 h-full">
<BarChart2 className="size-3 text-muted-foreground hover:text-primary cursor-pointer shrink-0" />
<TrendingUp className="size-3 text-muted-foreground hover:text-primary cursor-pointer shrink-0" />
<span className="text-[9.5px] text-[#ff9800] font-bold tabular-nums italic ml-0.5">{event.id || "01682"}</span>
</div>
{/* Time & Team Column */}
<div className="flex items-center gap-3 px-3 w-[240px] shrink-0 border-r border-border/10 h-full">
<div className="flex flex-col text-[9.5px] font-bold text-white leading-tight italic shrink-0 w-[45px]">
<span>11:00</span>
<span className="text-white/40 uppercase font-medium">PM</span>
</div>
<span className="text-[10px] font-bold text-white truncate max-w-[180px]">{event.homeTeam} - {event.awayTeam}</span>
</div>
{/* Market Columns Grid (10 Markets) */}
<div className="flex-1 grid grid-cols-10 h-full shrink-0">
{event.markets.slice(0, 10).map((market) => {
const betId = `${event.id}-${market.id}`
const isSelected = bets.some((b) => b.id === betId)
return (
<OddsButton
key={market.id}
odds={market.odds}
isSelected={isSelected}
onClick={() => addBet({
id: betId,
event: `${event.homeTeam} vs ${event.awayTeam}`,
league: event.league,
market: "1X2",
selection: `${event.homeTeam} (${market.label})`,
odds: market.odds,
})}
/>
)
})}
</div>
{/* More Markets Button */}
<button className="w-10 flex items-center justify-center h-full hover:bg-white/5 transition-colors border-l border-border/10 group">
<Plus className="size-3 text-white group-hover:scale-110 transition-transform" />
</button>
</div>
)
}
const MARKET_HEADERS = ["1", "x", "2", "Over (2.5)", "Under (2.5)", "1X", "12", "X2", "Yes", "No"];
export function EventsList({ filter = "All", sport = "all", search = "" }: {
filter?: string
sport?: string
search?: string
}) {
const searchParams = useSearchParams()
const leagueQuery = searchParams.get("league")
const [selectedLeague, setSelectedLeague] = useState<string | null>(leagueQuery)
const { bets, addBet } = useBetslipStore()
useEffect(() => {
setSelectedLeague(leagueQuery)
}, [leagueQuery])
const handleClose = () => {
const url = new URL(window.location.href)
url.searchParams.delete("league")
window.history.pushState({}, "", url)
setSelectedLeague(null)
}
const events = selectedLeague
? mockEvents.filter(e => e.league.toLowerCase() === selectedLeague.toLowerCase())
: mockEvents.filter((e) => {
if (filter === "Live" && !e.isLive) return false
if (sport !== "all" && e.sport.toLowerCase() !== sport.toLowerCase()) return false
return true
})
// Common Header Rendering
const renderTableHeaders = () => (
<>
{/* Table Header Categories */}
<div className="bg-[#1a1a1a] border-b border-border/40 grid grid-cols-5 text-[11px] font-bold text-white uppercase text-center items-center h-9">
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">Main</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">Goals</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">Handicap</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20 text-[9px] leading-tight">Half Time / Full Time</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer">Correct Score</div>
</div>
{/* Sub Headers */}
<div className="bg-[#1a1a1a] border-b border-border/40 grid grid-cols-5 text-[10px] font-bold text-white uppercase text-center items-center h-8">
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">1st Half</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">2nd Half</div>
<div className="h-full flex items-center justify-center bg-[#ff9800] text-black border-r border-border/10">Combo</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer border-r border-border/20">Chance Mix</div>
<div className="h-full flex items-center justify-center hover:bg-[#222] transition-colors cursor-pointer">Home</div>
</div>
</>
)
const renderColumnHeaders = () => (
<div className="bg-[#222] border-b border-white/5 h-8 flex items-center text-[9px] font-black text-white/40 uppercase">
<div className="w-[180px] px-3 flex items-center gap-1.5 border-r border-border/10 h-full">Main</div>
<div className="w-[180px] flex items-center justify-center border-r border-border/10 h-full">Over/Under</div>
<div className="flex-1 grid grid-cols-10 text-center h-full items-center tracking-tighter">
{MARKET_HEADERS.map(h => <span key={h}>{h}</span>)}
</div>
<div className="w-10 border-l border-border/10 h-full" />
</div>
)
const renderEventItem = (event: Event) => (
<div key={event.id} className="h-[34px] group flex items-center border-b border-white/5 bg-[#121212] hover:bg-white/5 transition-colors">
{/* Stats & Icons */}
<div className="w-[35px] flex items-center justify-center gap-1 px-2 border-r border-white/5 h-full opacity-40 group-hover:opacity-100">
<BarChart2 className="size-3 cursor-pointer hover:text-primary" />
</div>
{/* ID */}
<div className="w-[45px] text-[10px] font-black text-[#ff9800] italic tabular-nums text-center border-r border-white/5 h-full flex items-center justify-center">
{event.id}
</div>
{/* Time */}
<div className="w-[50px] flex flex-col items-center justify-center border-r border-white/5 h-full leading-none italic font-black text-[9px]">
<span>{event.time}</span>
<span className="text-[7px] text-white/30 uppercase mt-0.5">PM</span>
</div>
{/* Event Name */}
<div className="flex-1 px-4 text-[10.5px] font-black text-white truncate max-w-[200px]">
{event.homeTeam} - {event.awayTeam}
</div>
{/* Odds Grid */}
<div className="flex-1 grid grid-cols-10 h-full">
{event.markets.slice(0, 10).map((market) => {
const betId = `${event.id}-${market.id}`
const isSelected = bets.some((b) => b.id === betId)
return (
<button
key={market.id}
onClick={() => addBet({
id: betId,
event: `${event.homeTeam} vs ${event.awayTeam}`,
league: event.league,
market: "1X2",
selection: `${event.homeTeam} (${market.label})`,
odds: market.odds,
})}
className={cn(
"flex items-center justify-center text-[10.5px] font-black tabular-nums transition-all border-r border-white/5",
isSelected ? "bg-[#ff9800] text-black" : "text-[#ff9800] hover:bg-white/5"
)}
>
{market.odds.toFixed(2)}
</button>
)
})}
</div>
{/* More Button */}
<button className="w-10 flex items-center justify-center h-full hover:bg-white/5 transition-colors border-l border-white/5 text-white/40">
<Plus className="size-3" />
</button>
</div>
)
if (selectedLeague) {
// Group by date for league view
const groupedEvents = events.reduce((acc, event) => {
if (!acc[event.date]) acc[event.date] = []
acc[event.date].push(event)
return acc
}, {} as Record<string, Event[]>)
return (
<div className="flex flex-col bg-[#121212] rounded overflow-hidden shadow-2xl">
{/* League Header / Breadcrumbs */}
<div className="bg-[#1a1a1a] px-3 py-2 flex items-center justify-between border-b border-border/20">
<div className="flex items-center gap-2 text-[11px] font-bold text-white/60">
<Plus className="size-3 cursor-pointer hover:text-white" />
<div className="flex items-center gap-1.5">
<span className="text-white font-black"></span>
<span className="uppercase">Football</span>
<span className="mx-1 opacity-20">|</span>
<span className="text-white uppercase">{selectedLeague === "LaLiga" ? "Spain - LaLiga" : selectedLeague}</span>
</div>
</div>
<button onClick={handleClose} className="text-white hover:text-primary transition-colors">
<Plus className="size-5 rotate-45" />
</button>
</div>
{/* Large Market Tab Grid */}
<div className="grid grid-cols-5 bg-[#121212] border-b border-border/10">
{[
{ label: "Main", active: true }, { label: "Goals" }, { label: "Handicap" }, { label: "Half Time / Full Time" }, { label: "Correct Score" },
{ label: "1st Half" }, { label: "2nd Half" }, { label: "Asian Markets" }, { label: "Corners" }, { label: "Home" }
].map((m, i) => (
<button
key={i}
className={cn(
"h-8 border-r border-b border-border/10 flex items-center justify-center text-[10px] font-black uppercase transition-all",
m.active ? "bg-[#ff9800] text-black" : "text-white/60 hover:bg-[#222]"
)}
>
{m.label}
</button>
))}
</div>
{/* Column Headers */}
{renderColumnHeaders()}
{/* Grouped Events */}
<div className="overflow-y-auto max-h-[700px]">
{Object.entries(groupedEvents).map(([date, dateEvents]) => (
<div key={date} className="flex flex-col">
<div className="bg-[#1a1a1a] px-2 py-1 text-[10px] font-black text-white border-b border-white/5">
{date}
</div>
{dateEvents.map(event => renderEventItem(event))}
</div>
))}
</div>
</div>
)
}
// Home View (No League Selected)
const homeEventsByLeague = events.reduce((acc, event) => {
if (!acc[event.league]) acc[event.league] = []
acc[event.league].push(event)
return acc
}, {} as Record<string, Event[]>)
return (
<div className="flex flex-col bg-[#121212] rounded overflow-hidden">
<div className="flex flex-col">
{Object.entries(homeEventsByLeague).map(([leagueName, leagueEvents]) => (
<div key={leagueName} className="flex flex-col border-b border-white/5 last:border-none">
{/* League Box Header */}
<div className="bg-[#2a2a2a] px-3 py-1.5 text-[10px] font-bold text-[#ff9800] uppercase border-y border-border/20 flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-[14px]">
{popularLeagues.find(l => l.name === leagueName)?.icon ||
popularLeagues.find(l => l.id.toLowerCase() === leagueName.toLowerCase())?.icon ||
"⚽"}
</span>
<span>{leagueName === "LaLiga" ? "Spain - LaLiga" :
leagueName === "Premier League" ? "England - Premier League" :
leagueName === "Bundesliga" ? "Germany - Bundesliga" :
leagueName === "Ligue 1" ? "France - Ligue 1" :
leagueName}</span>
</div>
<ChevronDown className="size-4 text-white" />
</div>
{/* Column Headers for each league box */}
<div className="bg-[#222] px-3 py-1 flex items-center text-[8px] font-black text-white/40 uppercase border-b border-border/20">
<div className="w-[180px] flex gap-4">
<span className="w-5 text-center">Stats</span>
<span className="w-6">ID</span>
<span className="w-10">Time</span>
<span>Event</span>
</div>
<div className="flex-1 grid grid-cols-10 text-center tracking-tighter">
{MARKET_HEADERS.map(h => <span key={h}>{h}</span>)}
</div>
<div className="w-10" />
</div>
{/* Matches in this league */}
<div className="flex flex-col">
{leagueEvents.map(event => renderEventItem(event))}
</div>
</div>
))}
</div>
</div>
)
}

View File

@ -0,0 +1,62 @@
"use client"
import { useState, useEffect } from "react"
import { ChevronLeft, ChevronRight } from "lucide-react"
const images = [
"https://api-new.harifsport.com/home/img/editable/casj-1822.jpg",
"https://api-new.harifsport.com/home/img/editable/casj-18s.jpg"
]
export function HeroBanner() {
const [currentIndex, setCurrentIndex] = useState(0)
useEffect(() => {
const timer = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % images.length)
}, 5000)
return () => clearInterval(timer)
}, [])
return (
<div className="w-full h-[240px] md:h-[300px] relative overflow-hidden rounded-none group shadow-lg bg-[#111]">
{images.map((src, index) => (
<img
key={src}
src={src}
alt={`Banner ${index + 1}`}
className={`absolute inset-0 object-contain w-full h-full transition-opacity duration-1000 ${
index === currentIndex ? "opacity-100" : "opacity-0"
}`}
/>
))}
{/* Navigation Arrows */}
<button
onClick={() => setCurrentIndex((prev) => (prev - 1 + images.length) % images.length)}
className="absolute left-4 top-1/2 -translate-y-1/2 bg-black/60 p-2 text-white/80 hover:text-white transition-colors opacity-0 group-hover:opacity-100"
>
<ChevronLeft className="size-6" />
</button>
<button
onClick={() => setCurrentIndex((prev) => (prev + 1) % images.length)}
className="absolute right-4 top-1/2 -translate-y-1/2 bg-black/60 p-2 text-white/80 hover:text-white transition-colors opacity-0 group-hover:opacity-100"
>
<ChevronRight className="size-6" />
</button>
{/* Indicators */}
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-1.5 px-3 py-1.5 rounded-full bg-black/30 backdrop-blur-sm">
{images.map((_, index) => (
<button
key={index}
onClick={() => setCurrentIndex(index)}
className={`w-1.5 h-1.5 rounded-full transition-all ${
index === currentIndex ? "bg-[#ff9800] scale-125" : "bg-white/40"
}`}
/>
))}
</div>
</div>
)
}

View File

@ -1,11 +1,12 @@
export function InPlayHeader() {
return (
<div className="flex items-center justify-between border-b pb-2">
<h1 className="text-sm font-semibold uppercase tracking-wide text-foreground">
<div className="flex items-center justify-between border-b border-border pb-2">
<div className="flex items-center gap-2">
<h1 className="text-sm font-black uppercase tracking-wide text-foreground">
IN-PLAY
</h1>
<span className="text-[11px] text-muted-foreground">Quick Filter</span>
<span className="text-[10px] text-muted-foreground">/ Today&apos;s Events</span>
</div>
</div>
)
}

View File

@ -0,0 +1,195 @@
"use client"
import { useBetslipStore } from "@/lib/store/betslip-store"
import { mockEvents, type Event } from "@/lib/mock-data"
import { cn } from "@/lib/utils"
import { BarChart2, TrendingUp, Monitor, Tv } from "lucide-react"
function LiveEventRow({ event, isNoOdds }: { event: Event, isNoOdds?: boolean }) {
const { bets, addBet } = useBetslipStore()
// Dummy data for demonstration
const score = event.homeScore !== undefined ? `${event.homeScore} - ${event.awayScore}` : "0 - 0"
const time = event.liveMinute ? `${event.liveMinute}:00` : "83:10"
const period = "H2"
return (
<div className="bg-[#121212] border-b border-white/5 hover:bg-white/5 transition-colors h-[50px] flex items-center group">
{/* Match Info Column (Time & Score) */}
<div className="flex items-center gap-3 px-3 w-[360px] shrink-0 h-full border-r border-white/5">
<div className="flex flex-col text-[10px] font-black leading-tight italic w-[55px] shrink-0 tabular-nums">
<span className="text-[#ff9800]">{time}</span>
<span className="text-white/40">{period}</span>
</div>
<div className="flex items-center min-w-0 flex-1 gap-2">
<span className="text-[11.5px] font-black text-white truncate italic uppercase">
{event.homeTeam} <span className="text-[#ff9800] mx-1 tabular-nums">{score}</span> {event.awayTeam}
</span>
</div>
<div className="flex items-center gap-2 shrink-0 px-1 opacity-20 group-hover:opacity-100 transition-opacity">
<BarChart2 className="size-3.5 text-white" />
<Monitor className="size-3.5 text-white" />
</div>
</div>
{/* Odds Grid or Placeholder */}
<div className="flex-1 h-full flex items-center">
{isNoOdds ? (
<div className="flex-1 h-full bg-[#161616] flex items-center justify-center text-[10.5px] font-black text-white/20 uppercase italic tracking-tight">
Sorry, no odds for this match
</div>
) : (
<div className="flex-1 grid grid-cols-3 h-full">
{event.markets.slice(0, 3).map((m, idx) => {
const labels = ["Home", "Draw", "Away"]
return (
<button
key={m.id}
onClick={() => addBet({
id: `${event.id}-${m.id}`,
event: `${event.homeTeam} vs ${event.awayTeam}`,
league: event.league,
market: "1X2",
selection: `${m.label}`,
odds: m.odds,
})}
className="bg-[#1a1a1a] hover:bg-[#2a2a2a] flex items-center justify-between px-4 h-full border-r border-white/5 transition-colors group/btn"
>
<span className="text-[10px] font-black text-white/40 group-hover/btn:text-white uppercase">{labels[idx]}</span>
<span className="text-[11px] font-black text-[#ff9800] tabular-nums">{m.odds.toFixed(2)}</span>
</button>
)
})}
</div>
)}
</div>
{/* Right Indicator */}
<div className="w-[4px] bg-[#ff9800] h-full" />
</div>
)
}
const liveSports = [
{ id: "soccer", label: "Soccer", icon: "⚽", count: 25, active: true },
{ id: "basketball", label: "Basketball", icon: "🏀", count: 39 },
{ id: "ice-hockey", label: "Ice Hockey", icon: "🏒", count: 3 },
{ id: "tennis", label: "Tennis", icon: "🎾", count: 4 },
{ id: "handball", label: "Handball", icon: "🤾", count: 10 },
{ id: "rugby", label: "Rugby", icon: "🏉", count: 2 },
{ id: "table-tennis", label: "Table Tennis", icon: "🏓", count: 8 },
{ id: "volleyball", label: "Volleyball", icon: "🏐", count: 7 },
{ id: "futsal", label: "Futsal", icon: "⚽", count: 2 },
{ id: "esport-counter-strike", label: "ESport Cou...", icon: "🎮", count: 2 },
{ id: "esport-league-of-legends", label: "ESport Lea...", icon: "🎮", count: 1 },
{ id: "esport-dota-2", label: "ESport Dota", icon: "🎮", count: 1 },
{ id: "efootball", label: "eFootball", icon: "⚽", count: 4 },
{ id: "ebasketball", label: "eBasketball", icon: "🏀", count: 1 },
]
export function LiveEventsList() {
// Enhanced mock data local to live view to match screenshot exactly
const liveMatches = [
{
league: "Algeria - Ligue 1",
flag: "https://flagcdn.com/w20/dz.png",
matches: [
{ ...mockEvents[0], id: "l1", homeTeam: "Paradou AC", awayTeam: "Ben Aknoun", homeScore: 3, awayScore: 5, liveMinute: 91, noOdds: true }
]
},
{
league: "Australia - U23 Victoria NPL",
flag: "https://flagcdn.com/w20/au.png",
matches: [
{ ...mockEvents[1], id: "l2", homeTeam: "Oakleigh Cannons FC", awayTeam: "Altona Magic SC", homeScore: 5, awayScore: 1, liveMinute: 87, noOdds: true }
]
},
{
league: "Australia - U23 Victoria Premier League 1",
flag: "https://flagcdn.com/w20/au.png",
matches: [
{ ...mockEvents[2], id: "l3", homeTeam: "Northcote City FC", awayTeam: "Western United FC", homeScore: 4, awayScore: 0, liveMinute: 83, noOdds: false },
{ ...mockEvents[3], id: "l4", homeTeam: "Melbourne Knights FC", awayTeam: "Melbourne Victory FC", homeScore: 0, awayScore: 3, liveMinute: 81, noOdds: true }
]
},
{
league: "Australia - Victoria NPL, Women",
flag: "https://flagcdn.com/w20/au.png",
matches: [
{ ...mockEvents[4], id: "l5", homeTeam: "Preston Lions FC", awayTeam: "South Melbourne FC", homeScore: 1, awayScore: 1, liveMinute: 52, noOdds: true },
{ ...mockEvents[0], id: "l6", homeTeam: "Bentleigh Greens SC", awayTeam: "Box Hill United", homeScore: 0, awayScore: 6, liveMinute: 83, noOdds: true }
]
}
]
return (
<div className="flex flex-col min-h-screen bg-[#111]">
{/* Sport Navigation Carousel */}
<div className="bg-[#1a1a1a] border-b border-border/20 px-2 flex items-center h-[54px] overflow-x-auto scrollbar-hide">
<div className="flex items-center gap-0 h-full">
{/* Favourites & Prematch */}
<button className="flex flex-col items-center justify-center px-4 h-full border-r border-white/5 min-w-[70px]">
<span className="text-[14px]"></span>
<span className="text-[9px] font-bold text-white/40 uppercase mt-0.5">Favourites</span>
</button>
<button className="flex flex-col items-center justify-center px-4 h-full border-r border-white/5 min-w-[70px]">
<span className="text-[14px]"></span>
<span className="text-[9px] font-bold text-white/40 uppercase mt-0.5">Prematch</span>
</button>
{/* Live Sports */}
{liveSports.map((sport) => (
<button
key={sport.id}
className={cn(
"flex flex-col items-center justify-center px-3 h-full border-r border-white/5 min-w-[75px] relative transition-colors",
sport.active ? "bg-black/20" : "hover:bg-white/5"
)}
>
<span className="absolute top-1 right-2 text-[8.5px] font-black text-white/40">{sport.count}</span>
<span className="text-[16px]">{sport.icon}</span>
<span className={cn(
"text-[9px] font-bold uppercase mt-1 tracking-tighter whitespace-nowrap",
sport.active ? "text-[#ff9800]" : "text-white/40"
)}>
{sport.label}
</span>
{sport.active && (
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-[#ff9800]" />
)}
</button>
))}
</div>
</div>
{/* Category Header (Soccer) */}
<div className="bg-[#009688] px-3 py-1.5 flex items-center gap-2 border-l-[4px] border-[#ff9800]">
<span className="text-[16px]"></span>
<h2 className="text-[14px] font-black text-white uppercase tracking-tight">Soccer</h2>
</div>
{/* Grouped Live Matches */}
<div className="flex flex-col mb-10">
{liveMatches.map((group, gIdx) => (
<div key={gIdx} className="flex flex-col">
{/* League Header */}
<div className="bg-[#1a1a1a] px-3 py-1 border-b border-border/10 flex items-center gap-2">
<img src={group.flag} width="14" alt={group.league} className="rounded-sm opacity-60" />
<span className="text-[9.5px] font-black text-white/60 uppercase tracking-widest leading-none">
{group.league}
</span>
</div>
{/* Matches in this league */}
<div className="flex flex-col">
{group.matches.map((match, mIdx) => (
<LiveEventRow key={match.id} event={match as any} isNoOdds={match.noOdds} />
))}
</div>
</div>
))}
</div>
</div>
)
}

View File

@ -1,18 +1,32 @@
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
"use client"
const filters = ["All", "Today", "3h", "6h", "9h", "12h"]
import { cn } from "@/lib/utils"
export function QuickFilterBar() {
const filters = ["All", "Live", "Today", "3h", "6h", "12h"]
export function QuickFilterBar({ active, onChange }: {
active: string
onChange: (f: string) => void
}) {
return (
<Tabs defaultValue="All" className="w-full">
<TabsList className="h-8">
<div className="flex items-center gap-1 overflow-x-auto pb-0.5">
{filters.map((filter) => (
<TabsTrigger key={filter} value={filter} className="px-3 text-xs">
<button
key={filter}
onClick={() => onChange(filter)}
className={cn(
"shrink-0 px-3 py-1 rounded text-[11px] font-semibold transition-colors",
active === filter
? "bg-primary text-primary-foreground"
: "bg-secondary text-muted-foreground hover:bg-muted hover:text-foreground"
)}
>
{filter}
</TabsTrigger>
{filter === "Live" && (
<span className="ml-1 live-dot inline-block size-1.5 rounded-full bg-[var(--hs-live-red)] align-middle" />
)}
</button>
))}
</TabsList>
</Tabs>
</div>
)
}

View File

@ -1,28 +1,27 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
"use client"
import { useState } from "react"
export function ReloadTicket() {
const [code, setCode] = useState("")
return (
<Card>
<CardHeader>
<CardTitle className="text-sm">Reload Ticket</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-xs">
<div className="text-[11px] text-muted-foreground">
Insert the code to load
</div>
<div className="flex gap-2">
<Input
placeholder="Ticket code"
className="h-8 text-xs placeholder:text-[11px]"
<div className="bg-transparent border-t border-border/20 pt-4 pb-2">
<div className="px-1 text-center space-y-3">
<h3 className="text-[12px] font-bold uppercase text-[#ff9800]">Reload Ticket</h3>
<p className="text-[11px] text-white">Insert the code to load</p>
<div className="flex gap-1">
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
className="flex-1 bg-[#121212] border border-border/40 px-2 py-2 text-[11px] text-white outline-none focus:border-primary"
/>
<Button size="sm" className="text-xs">
Reload
</Button>
<button className="bg-[#ff9800] text-black px-2 py-1.5 flex items-center justify-center min-w-[32px] hover:bg-[#ffa726] transition-colors">
<svg viewBox="0 0 24 24" className="size-5 fill-current"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
</button>
</div>
</div>
</div>
</CardContent>
</Card>
)
}

View File

@ -1,19 +1,21 @@
import { Input } from "@/components/ui/input"
"use client"
export function SearchEvent() {
import { Search } from "lucide-react"
export function SearchEvent({ value, onChange }: {
value: string
onChange: (v: string) => void
}) {
return (
<div className="space-y-1 rounded-md border bg-card/60 p-3">
<div className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
Search Event
</div>
<p className="text-[11px] text-muted-foreground">
Insert the events name or at least one team in the form below
</p>
<Input
placeholder="Search by event or team"
className="h-8 text-xs placeholder:text-[11px]"
<div className="relative">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground" />
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Search by event, team or league..."
className="w-full bg-secondary border border-border rounded pl-8 pr-3 py-2 text-[12px] text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-primary transition-colors"
/>
</div>
)
}

View File

@ -0,0 +1,27 @@
"use client"
import { useSearchParams } from "next/navigation"
import { HeroBanner } from "./hero-banner"
import { TopMatches } from "./top-matches"
import { SportsNav } from "./sports-nav"
import { HomeTabs } from "./home-tabs"
import { EventsList } from "./events-list"
export function SportHome() {
const searchParams = useSearchParams()
const isLeagueView = !!searchParams.get("league")
return (
<div className="flex flex-col gap-3">
{!isLeagueView && (
<>
<HeroBanner />
<TopMatches />
<SportsNav />
<HomeTabs />
</>
)}
<EventsList />
</div>
)
}

View File

@ -0,0 +1,33 @@
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
const sports = [
{ id: "football", name: "Football", icon: "⚽" },
{ id: "tennis", name: "Tennis", icon: "🎾" },
{ id: "basketball", name: "Basketball", icon: "🏀" },
{ id: "ice-hockey", name: "Ice Hockey", icon: "🏒" },
{ id: "mma", name: "MMA", icon: "🥋" },
{ id: "handball", name: "Handball", icon: "🤾" },
{ id: "darts", name: "Darts", icon: "🎯" },
{ id: "snooker", name: "Snooker", icon: "🎱" },
{ id: "cricket", name: "Cricket", icon: "🏏" },
{ id: "dota2", name: "Dota 2", icon: "🎮" },
]
export function SportsNav() {
return (
<Tabs defaultValue="football" className="w-full">
<TabsList variant="hs-nav" className="h-auto">
{sports.map((sport) => (
<TabsTrigger
key={sport.id}
value={sport.id}
className="flex-col min-w-[70px] py-2 gap-1"
>
<span className="text-xl">{sport.icon}</span>
<span className="text-[10px] font-bold uppercase">{sport.name}</span>
</TabsTrigger>
))}
</TabsList>
</Tabs>
)
}

View File

@ -0,0 +1,102 @@
import { ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
const topMatches = [
{
id: "tm1",
league: "England - Premier League",
time: "05:00 PM",
homeTeam: "Nottingham Forest",
awayTeam: "Liverpool",
odds: { home: 4.09, draw: 3.93, away: 1.82 }
},
{
id: "tm2",
league: "England - Premier League",
time: "11:00 PM",
homeTeam: "Man City",
awayTeam: "Newcastle",
odds: { home: 1.50, draw: 5.17, away: 5.93 }
},
{
id: "tm3",
league: "England - Premier League",
time: "06:00 PM",
homeTeam: "Chelsea",
awayTeam: "Burnley",
odds: { home: 1.21, draw: 6.91, away: 11.50 }
},
{
id: "tm4",
league: "Spain - LaLiga",
time: "07:30 PM",
homeTeam: "Arsenal",
awayTeam: "Wolves",
odds: { home: 1.56, draw: 4.16, away: 5.80 }
},
{
id: "tm5",
league: "Italy - Serie A",
time: "09:45 PM",
homeTeam: "Inter Milan",
awayTeam: "Napoli",
odds: { home: 1.85, draw: 3.60, away: 4.20 }
}
]
export function TopMatches() {
return (
<div className="flex gap-3 overflow-x-auto pb-2 scrollbar-hide -mx-1 px-1">
{topMatches.map((match) => (
<div
key={match.id}
className="min-w-[280px] bg-[#222] border border-border/20 rounded-sm overflow-hidden flex flex-col relative group"
>
{/* Top Label Ribbon */}
<div className="absolute top-0 right-0 w-12 h-12 overflow-hidden z-10 pointer-events-none">
<div className="absolute top-[6px] right-[-14px] bg-[#ff9800] text-black text-[8px] font-black py-0.5 px-6 rotate-45 shadow-sm uppercase tracking-tighter">
TOP
</div>
</div>
<div className="bg-[#1a1a1a] px-3 py-1.5 flex items-center justify-between text-[10px] text-muted-foreground border-b border-border/10">
<div className="flex items-center gap-1">
<span className="font-bold text-[#ff9800]">{match.league}</span>
<span className="font-black text-white ml-1 italic">{match.time}</span>
</div>
<ChevronRight className="size-3 text-white/20 mr-4" />
</div>
<div className="p-3 flex flex-col gap-3">
<div className="flex items-center justify-between gap-1">
<div className="flex items-center gap-2 flex-1 min-w-0">
<div className="size-4 shrink-0 bg-white/5 rounded-sm flex items-center justify-center text-[9px] border border-white/10"></div>
<span className="text-[11px] font-black text-white truncate uppercase italic">{match.homeTeam}</span>
</div>
<span className="text-[#ff9800] text-[9.5px] font-black italic shrink-0 px-2 opacity-60">VS</span>
<div className="flex items-center gap-2 flex-1 min-w-0 justify-end">
<span className="text-[11px] font-black text-white truncate uppercase italic text-right">{match.awayTeam}</span>
<div className="size-4 shrink-0 bg-white/5 rounded-sm flex items-center justify-center text-[9px] border border-white/10"></div>
</div>
</div>
</div>
<div className="grid grid-cols-3 gap-[1px] bg-white/5 mx-2 mb-2 rounded-sm overflow-hidden border border-white/5">
<button className="bg-[#1a1a1a] hover:bg-[#333] flex items-center justify-between px-2.5 py-1.5 transition-colors group/btn">
<span className="text-[10px] font-black text-white/40 group-hover/btn:text-white">1</span>
<span className="text-[11px] font-black text-[#ff9800] tabular-nums">{match.odds.home.toFixed(2)}</span>
</button>
<button className="bg-[#1a1a1a] hover:bg-[#333] flex items-center justify-between px-2.5 py-1.5 transition-colors border-x border-white/5 group/btn">
<span className="text-[10px] font-black text-white/40 group-hover/btn:text-white">X</span>
<span className="text-[11px] font-black text-[#ff9800] tabular-nums">{match.odds.draw.toFixed(2)}</span>
</button>
<button className="bg-[#1a1a1a] hover:bg-[#333] flex items-center justify-between px-2.5 py-1.5 transition-colors group/btn">
<span className="text-[10px] font-black text-white/40 group-hover/btn:text-white">2</span>
<span className="text-[11px] font-black text-[#ff9800] tabular-nums">{match.odds.away.toFixed(2)}</span>
</button>
</div>
</div>
))}
</div>
)
}

View File

@ -1,32 +1,164 @@
const sports = [
"Soccer",
"Basketball",
"Tennis",
"Ice Hockey",
"Volleyball",
"Handball",
"Baseball",
"American Football",
"Cricket",
"Rugby",
"use client"
import { useState } from "react"
import Link from "next/link"
import { popularLeagues } from "@/lib/mock-data"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
const sportCategories = [
{ id: "football", name: "Football", icon: "⚽", count: 1412 },
{ id: "tennis", name: "Tennis", icon: "🎾", count: 67 },
{ id: "basketball", name: "Basketball", icon: "🏀", count: 255 },
{ id: "ice-hockey", name: "Ice Hockey", icon: "🏒", count: 238 },
{ id: "mma", name: "MMA", icon: "🥊", count: 51 },
{ id: "handball", name: "Handball", icon: "🤾", count: 92 },
{ 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 },
]
export function SportsSidebar() {
return (
<aside className="hidden h-full w-52 shrink-0 border-r bg-sidebar px-3 py-3 text-sm text-sidebar-foreground lg:block">
<div className="mb-3 font-semibold uppercase tracking-wide text-xs text-muted-foreground">
Sports Menu
</div>
<ul className="space-y-1">
{sports.map((sport) => (
<li key={sport}>
<button className="w-full rounded px-2 py-1 text-left text-xs text-muted-foreground hover:bg-muted hover:text-foreground">
{sport}
</button>
</li>
))}
</ul>
</aside>
);
}
const [activeSport, setActiveSport] = useState("football")
return (
<aside className="hidden h-full w-[240px] shrink-0 bg-[#262626] lg:block overflow-y-auto border-r border-border/40 scrollbar-hide">
{/* Sports Menu Header */}
<div className="bg-[#1a1a1a] px-3 py-2 text-[11px] font-black text-[#ff9800] uppercase tracking-tighter flex items-center justify-between border-b border-border/30">
Sports Menu
<svg viewBox="0 0 24 24" className="size-3.5 fill-current opacity-60"><path d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"/></svg>
</div>
{/* Top Leagues Header */}
<div className="bg-[#262626] px-3 py-2.5 text-[11px] font-black text-[#ff9800] uppercase text-center border-b border-border/20 flex items-center justify-center gap-2">
Top Leagues
</div>
{/* Popular Leagues */}
<div className="flex flex-col">
{popularLeagues.map((league) => (
<Link
key={league.id}
href={`/?league=${league.id}`}
className="w-full flex items-center justify-between px-3 py-2 text-left text-white/90 hover:bg-[#333] transition-colors border-b border-border/10 group h-9"
>
<div className="flex items-center gap-2.5 min-w-0">
<div className="size-4 shrink-0 overflow-hidden rounded-sm flex items-center justify-center bg-white/10 group-hover:bg-white/20 transition-colors">
{league.logo ? (
<img src={league.logo} alt="" className="size-full object-contain" />
) : (
<span className="text-[10px] leading-none invert"></span>
)}
</div>
<span className="text-[10.5px] font-bold leading-tight truncate max-w-[150px]">{league.name}</span>
</div>
<div className="size-3.5 rounded-full border border-white/20 flex items-center justify-center group-hover:border-[#ff9800] transition-colors shrink-0">
<div className="size-1.5 bg-white/40 rounded-full group-hover:bg-[#ff9800]" />
</div>
</Link>
))}
</div>
{/* In-Play Strip */}
<Button className="w-full bg-[#004d40] text-[#00bfa5] hover:bg-[#003d33] border-none py-2.5 h-auto text-[11px] font-black uppercase rounded-none tracking-[2px]">
<span className="size-2 rounded-full bg-[#ff9800] mr-2 live-dot shadow-[0_0_8px_#ff9800]"></span>
IN-PLAY
</Button>
{/* Quick Filter Section */}
<div className="bg-[#1a1a1a] p-3 border-b border-border/30">
<span className="text-[#ff9800] 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-[#333] text-white" : "bg-[#2a2a2a] text-white/50 hover:text-white"
)}>{t}</button>
))}
</div>
</div>
{/* Search Event Section */}
<div className="bg-[#1a1a1a] p-3 border-b border-border/40">
<span className="text-[#ff9800] text-[10.5px] uppercase font-black block mb-1 tracking-tight">Search Event</span>
<p className="text-[9px] text-white/30 mb-2 leading-tight font-medium uppercase">Insert the events name or at least one team in the form below</p>
<div className="flex flex-col gap-1.5">
<div className="relative">
<input type="text" className="bg-[#2a2a2a] border-none text-white text-[11px] px-3 py-2 w-full focus:ring-0 placeholder:text-white/20" placeholder="Search" />
</div>
<Button className="bg-[#ff9800] text-black hover:bg-[#e68900] py-2 h-auto rounded-none text-[11px] font-black uppercase tracking-wider">Search</Button>
</div>
</div>
{/* Sport categories */}
<div className="divide-y divide-border/10 bg-[#262626]">
{sportCategories.map((sport) => (
<button
key={sport.id}
onClick={() => setActiveSport(sport.id)}
className={cn(
"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
? "bg-[#333] text-white"
: "text-white/70 hover:bg-[#333] hover:text-white"
)}
>
<div className="flex items-center gap-3">
<span className="text-[12px] opacity-80 shrink-0">{sport.icon}</span>
<span className="text-[10.5px] font-bold tracking-tight">{sport.name}</span>
</div>
<div className="flex items-center gap-2">
<span className="text-[10px] font-bold text-white/40">{sport.count}</span>
<span className="text-[11px] text-white/20"></span>
</div>
</button>
))}
</div>
{/* Bet Services */}
<div className="mt-2 text-[11px] font-bold text-[#ff9800] px-3 py-2 uppercase border-y border-border/20 bg-[#1a1a1a]">
Bet Services
</div>
<div className="grid grid-cols-3 gap-0 border-b border-border/10">
<Button variant="ghost" className="flex flex-col items-center justify-center py-4 h-auto rounded-none border-r border-border/10 hover:bg-[#333] group">
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-[#ff9800] transition-colors"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm3.3 14.71L11 12.41V7h2v4.59l3.71 3.71-1.42 1.41z"/></svg>
<span className="text-[9px] text-white font-medium">Live Score</span>
</Button>
<Button variant="ghost" className="flex flex-col items-center justify-center py-4 h-auto rounded-none border-r border-border/10 hover:bg-[#333] group">
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-[#ff9800] transition-colors"><path d="M5 9.2h3V19H5zM10.6 5h2.8v14h-2.8zm5.6 8H19v6h-2.8z"/></svg>
<span className="text-[9px] text-white font-medium">Results</span>
</Button>
<Button variant="ghost" className="flex flex-col items-center justify-center py-4 h-auto rounded-none hover:bg-[#333] group">
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-[#ff9800] transition-colors"><path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z"/></svg>
<span className="text-[9px] text-white font-medium">Print Odds</span>
</Button>
</div>
<div className="p-2 space-y-1">
<Button className="w-full bg-[#004d40] text-[#00bfa5] hover:bg-[#003d33] border-none py-2 h-auto text-[11px] font-bold uppercase rounded-none tracking-widest">
<span className="size-2 rounded-full bg-[#ff9800] mr-2 live-dot"></span>
IN-PLAY
</Button>
<div className="bg-[#1a1a1a] p-3 border border-border/10">
<span className="text-[#ff9800] text-[10px] uppercase font-bold block mb-2">Quick Filter</span>
<div className="grid grid-cols-6 gap-0.5">
{["All", "Today", "3h", "6h", "9h", "12h"].map((t) => (
<button key={t} className="text-[9px] py-1 bg-[#2a2a2a] text-white/70 hover:bg-[#333] transition-colors">{t}</button>
))}
</div>
</div>
<div className="bg-[#1a1a1a] p-3 border border-border/10">
<span className="text-[#ff9800] text-[10px] uppercase font-bold block mb-2">Search Event</span>
<p className="text-[9px] text-white/40 mb-2 leading-tight">Insert the events name or at least one team in the form below</p>
<div className="flex flex-col gap-1.5">
<input type="text" className="bg-[#2a2a2a] border-none text-white text-[10px] px-2 py-1.5 focus:ring-0" placeholder="Search" />
<Button className="bg-[#333] text-white hover:bg-[#444] py-1.5 h-auto rounded-none text-[10px] font-bold uppercase">Search</Button>
</div>
</div>
</div>
</aside>
)
}