From 612bb9386b9164ba4264c18c3fa99fca27d93c29 Mon Sep 17 00:00:00 2001 From: brooktewabe Date: Fri, 20 Feb 2026 12:22:04 +0300 Subject: [PATCH] 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. --- components/betting/bet-services.tsx | 34 ++- components/betting/betslip.tsx | 215 +++++++++++--- components/betting/check-your-bet.tsx | 70 +++-- components/betting/events-list.tsx | 378 +++++++++++++++++++----- components/betting/hero-banner.tsx | 62 ++++ components/betting/in-play-header.tsx | 15 +- components/betting/live-events-list.tsx | 195 ++++++++++++ components/betting/quick-filter-bar.tsx | 42 ++- components/betting/reload-ticket.tsx | 49 ++- components/betting/search-event.tsx | 30 +- components/betting/sport-home.tsx | 27 ++ components/betting/sports-nav.tsx | 33 +++ components/betting/top-matches.tsx | 102 +++++++ components/layout/sports-sidebar.tsx | 188 ++++++++++-- 14 files changed, 1194 insertions(+), 246 deletions(-) create mode 100644 components/betting/hero-banner.tsx create mode 100644 components/betting/live-events-list.tsx create mode 100644 components/betting/sport-home.tsx create mode 100644 components/betting/sports-nav.tsx create mode 100644 components/betting/top-matches.tsx diff --git a/components/betting/bet-services.tsx b/components/betting/bet-services.tsx index 0955774..168650c 100644 --- a/components/betting/bet-services.tsx +++ b/components/betting/bet-services.tsx @@ -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 ( -
- - Bet Services +
+ + Services - -
- {services.map((service) => ( + {services.map((service, i) => { + const Icon = service.icon + return ( - ))} -
+ ) + })}
) -} - +} \ No newline at end of file diff --git a/components/betting/betslip.tsx b/components/betting/betslip.tsx index 1b66c5e..a5427f4 100644 --- a/components/betting/betslip.tsx +++ b/components/betting/betslip.tsx @@ -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 ( - - - - Betslip {bets.length} - +
+ {/* Header */} +
+
+ Betslip + {bets.length > 0 && ( + + {bets.length} + + )} +
{bets.length > 0 && ( )} - - +
+ + {/* Tabs */} + {bets.length > 1 && ( +
+ {(["single", "accumulator"] as const).map((tab) => ( + + ))} +
+ )} + + {/* Content */} +
{bets.length === 0 ? ( -

- No bet has been selected. To select a bet, please click on the - respective odds. -

+
+
🎯
+

+ No bets selected. Click on odds to add selections. +

+
) : ( -
- {bets.map((bet) => ( -
-
-
-
{bet.event}
-
- {bet.market} – {bet.selection} + <> + {/* Bet items */} +
+ {bets.map((bet) => ( +
+
+
+
{bet.event}
+
{bet.league}
+
+ {bet.market}: {bet.selection} +
+
+
+ {bet.odds.toFixed(2)} +
-
-
{bet.odds.toFixed(2)}
- + + {/* Stake input for single */} + {(activeTab === "single" || bets.length === 1) && ( +
+
Stake (ETB)
+
+ 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" + /> +
+
+ {quickStakes.map((s) => ( + + ))} +
+ {/* Potential win */} +
+ Potential win: + + {((bet.stake ?? 10) * bet.odds).toFixed(2)} ETB + +
+
+ )} +
+ ))} +
+ + {/* Accumulator stake section */} + {activeTab === "accumulator" && bets.length > 1 && ( +
+
+ Total Odds: + {totalOdds.toFixed(2)} +
+
+
Stake (ETB)
+ 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" + /> +
+ {quickStakes.map((s) => ( + + ))} +
+
+ Potential win: + + {(Number(globalStake) * totalOdds).toFixed(2)} ETB +
- ))} - -
- )} - - - ); -} + )} + {/* Place bet button */} + + + )} +
+
+ ) +} \ No newline at end of file diff --git a/components/betting/check-your-bet.tsx b/components/betting/check-your-bet.tsx index 6fee384..9970b13 100644 --- a/components/betting/check-your-bet.tsx +++ b/components/betting/check-your-bet.tsx @@ -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() { - return ( - - - Check your bet - - -
Your bet ID
-
- - -
-
-
- ) -} + const [betId, setBetId] = useState("") + const [result, setResult] = useState(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 ( +
+
+

Check Your Bet

+

Your bet ID

+
+ 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()} + /> + +
+ {result && ( +
+ {result === "won" && "🎉 Bet Won!"} + {result === "lost" && "❌ Bet Lost"} + {result === "pending" && "⏳ Bet Pending"} +
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/components/betting/events-list.tsx b/components/betting/events-list.tsx index 6b215a4..9fc1729 100644 --- a/components/betting/events-list.tsx +++ b/components/betting/events-list.tsx @@ -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 ( - - - -
- {mockEvents.map((event) => ( -
-
-
-
{event.name}
-
- {event.sport} -
-
-
-
- {event.markets.map((market) => ( - - ))} -
-
- ))} -
-
-
-
+ ) } +function EventRow({ event }: { event: Event }) { + const { bets, addBet } = useBetslipStore() + + return ( +
+ {/* Small Icons & ID Column */} +
+ + + {event.id || "01682"} +
+ + {/* Time & Team Column */} +
+
+ 11:00 + PM +
+ {event.homeTeam} - {event.awayTeam} +
+ + {/* Market Columns Grid (10 Markets) */} +
+ {event.markets.slice(0, 10).map((market) => { + const betId = `${event.id}-${market.id}` + const isSelected = bets.some((b) => b.id === betId) + return ( + addBet({ + id: betId, + event: `${event.homeTeam} vs ${event.awayTeam}`, + league: event.league, + market: "1X2", + selection: `${event.homeTeam} (${market.label})`, + odds: market.odds, + })} + /> + ) + })} +
+ + {/* More Markets Button */} + +
+ ) +} + +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(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 */} +
+
Main
+
Goals
+
Handicap
+
Half Time / Full Time
+
Correct Score
+
+ {/* Sub Headers */} +
+
1st Half
+
2nd Half
+
Combo
+
Chance Mix
+
Home
+
+ + ) + + const renderColumnHeaders = () => ( +
+
Main
+
Over/Under
+
+ {MARKET_HEADERS.map(h => {h})} +
+
+
+ ) + + const renderEventItem = (event: Event) => ( +
+ {/* Stats & Icons */} +
+ +
+ {/* ID */} +
+ {event.id} +
+ {/* Time */} +
+ {event.time} + PM +
+ {/* Event Name */} +
+ {event.homeTeam} - {event.awayTeam} +
+ {/* Odds Grid */} +
+ {event.markets.slice(0, 10).map((market) => { + const betId = `${event.id}-${market.id}` + const isSelected = bets.some((b) => b.id === betId) + return ( + + ) + })} +
+ {/* More Button */} + +
+ ) + + 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) + + return ( +
+ {/* League Header / Breadcrumbs */} +
+
+ +
+ ••• + Football + | + {selectedLeague === "LaLiga" ? "Spain - LaLiga" : selectedLeague} +
+
+ +
+ + {/* Large Market Tab Grid */} +
+ {[ + { 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) => ( + + ))} +
+ + {/* Column Headers */} + {renderColumnHeaders()} + + {/* Grouped Events */} +
+ {Object.entries(groupedEvents).map(([date, dateEvents]) => ( +
+
+ {date} +
+ {dateEvents.map(event => renderEventItem(event))} +
+ ))} +
+
+ ) + } + + // 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) + + return ( +
+
+ {Object.entries(homeEventsByLeague).map(([leagueName, leagueEvents]) => ( +
+ {/* League Box Header */} +
+
+ + {popularLeagues.find(l => l.name === leagueName)?.icon || + popularLeagues.find(l => l.id.toLowerCase() === leagueName.toLowerCase())?.icon || + "⚽"} + + {leagueName === "LaLiga" ? "Spain - LaLiga" : + leagueName === "Premier League" ? "England - Premier League" : + leagueName === "Bundesliga" ? "Germany - Bundesliga" : + leagueName === "Ligue 1" ? "France - Ligue 1" : + leagueName} +
+ +
+ + {/* Column Headers for each league box */} +
+
+ Stats + ID + Time + Event +
+
+ {MARKET_HEADERS.map(h => {h})} +
+
+
+ + {/* Matches in this league */} +
+ {leagueEvents.map(event => renderEventItem(event))} +
+
+ ))} +
+
+ ) +} diff --git a/components/betting/hero-banner.tsx b/components/betting/hero-banner.tsx new file mode 100644 index 0000000..28cc6e6 --- /dev/null +++ b/components/betting/hero-banner.tsx @@ -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 ( +
+ {images.map((src, index) => ( + {`Banner + ))} + + {/* Navigation Arrows */} + + + + {/* Indicators */} +
+ {images.map((_, index) => ( +
+
+ ) +} diff --git a/components/betting/in-play-header.tsx b/components/betting/in-play-header.tsx index 0d1cd62..2ad4b5e 100644 --- a/components/betting/in-play-header.tsx +++ b/components/betting/in-play-header.tsx @@ -1,11 +1,12 @@ export function InPlayHeader() { return ( -
-

- IN-PLAY -

- Quick Filter +
+
+

+ IN-PLAY +

+ / Today's Events +
) -} - +} \ No newline at end of file diff --git a/components/betting/live-events-list.tsx b/components/betting/live-events-list.tsx new file mode 100644 index 0000000..5615e9a --- /dev/null +++ b/components/betting/live-events-list.tsx @@ -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 ( +
+ {/* Match Info Column (Time & Score) */} +
+
+ {time} + {period} +
+
+ + {event.homeTeam} {score} {event.awayTeam} + +
+
+ + +
+
+ + {/* Odds Grid or Placeholder */} +
+ {isNoOdds ? ( +
+ Sorry, no odds for this match +
+ ) : ( +
+ {event.markets.slice(0, 3).map((m, idx) => { + const labels = ["Home", "Draw", "Away"] + return ( + + ) + })} +
+ )} +
+ + {/* Right Indicator */} +
+
+ ) +} + +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 ( +
+ {/* Sport Navigation Carousel */} +
+
+ {/* Favourites & Prematch */} + + + + {/* Live Sports */} + {liveSports.map((sport) => ( + + ))} +
+
+ + {/* Category Header (Soccer) */} +
+ +

Soccer

+
+ + {/* Grouped Live Matches */} +
+ {liveMatches.map((group, gIdx) => ( +
+ {/* League Header */} +
+ {group.league} + + {group.league} + +
+ + {/* Matches in this league */} +
+ {group.matches.map((match, mIdx) => ( + + ))} +
+
+ ))} +
+
+ ) +} diff --git a/components/betting/quick-filter-bar.tsx b/components/betting/quick-filter-bar.tsx index 41c422b..7568d1d 100644 --- a/components/betting/quick-filter-bar.tsx +++ b/components/betting/quick-filter-bar.tsx @@ -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 ( - - - {filters.map((filter) => ( - - {filter} - - ))} - - +
+ {filters.map((filter) => ( + + ))} +
) -} - +} \ No newline at end of file diff --git a/components/betting/reload-ticket.tsx b/components/betting/reload-ticket.tsx index 91d501f..9ab5e60 100644 --- a/components/betting/reload-ticket.tsx +++ b/components/betting/reload-ticket.tsx @@ -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() { - return ( - - - Reload Ticket - - -
- Insert the code to load -
-
- - -
-
-
- ) -} + const [code, setCode] = useState("") + return ( +
+
+

Reload Ticket

+

Insert the code to load

+
+ 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" + /> + +
+
+
+ ) +} \ No newline at end of file diff --git a/components/betting/search-event.tsx b/components/betting/search-event.tsx index 65f5e87..339994e 100644 --- a/components/betting/search-event.tsx +++ b/components/betting/search-event.tsx @@ -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 ( -
-
- Search Event -
-

- Insert the events name or at least one team in the form below -

- + + 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" />
) -} - +} \ No newline at end of file diff --git a/components/betting/sport-home.tsx b/components/betting/sport-home.tsx new file mode 100644 index 0000000..172f5e6 --- /dev/null +++ b/components/betting/sport-home.tsx @@ -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 ( +
+ {!isLeagueView && ( + <> + + + + + + )} + +
+ ) +} diff --git a/components/betting/sports-nav.tsx b/components/betting/sports-nav.tsx new file mode 100644 index 0000000..44c3332 --- /dev/null +++ b/components/betting/sports-nav.tsx @@ -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 ( + + + {sports.map((sport) => ( + + {sport.icon} + {sport.name} + + ))} + + + ) +} diff --git a/components/betting/top-matches.tsx b/components/betting/top-matches.tsx new file mode 100644 index 0000000..824e905 --- /dev/null +++ b/components/betting/top-matches.tsx @@ -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 ( +
+ {topMatches.map((match) => ( +
+ {/* Top Label Ribbon */} +
+
+ TOP +
+
+ +
+
+ {match.league} + {match.time} +
+ +
+ +
+
+
+
+ {match.homeTeam} +
+ VS +
+ {match.awayTeam} +
+
+
+
+ +
+ + + +
+
+ ))} +
+ ) +} diff --git a/components/layout/sports-sidebar.tsx b/components/layout/sports-sidebar.tsx index ccb57b6..fc7b7e5 100644 --- a/components/layout/sports-sidebar.tsx +++ b/components/layout/sports-sidebar.tsx @@ -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 ( - - ); -} + const [activeSport, setActiveSport] = useState("football") + return ( + + ) +}