This commit is contained in:
brooktewabe 2026-03-01 14:24:30 +03:00
parent bad08b229e
commit 463cabbdd0
8 changed files with 206 additions and 126 deletions

View File

@ -66,39 +66,41 @@ export function AuthModal({ open, defaultMode, onClose }: AuthModalProps) {
onClick={onClose}
>
<div
className="relative w-[420px] bg-brand-surface-light shadow-2xl animate-fade-in"
className="relative w-[280px] bg-brand-surface-light shadow-2xl animate-fade-in"
onClick={(e) => e.stopPropagation()}
>
{/* Close button */}
<button
onClick={onClose}
className="absolute top-2 right-3 text-white/60 hover:text-white text-xl leading-none transition-colors z-10"
className="absolute top-1 right-2 text-white/60 hover:text-white text-lg leading-none transition-colors z-10"
aria-label="Close"
>
×
</button>
{/* Logo */}
<div className="flex items-center justify-center py-5 border-b border-white/10 bg-brand-surface">
<div className="flex items-center justify-center py-4 border-b border-white/10 bg-brand-surface">
<div className="scale-75 origin-center">
<Logo />
</div>
</div>
{/* Title */}
<div className="text-center py-4">
<h2 className="text-sm font-black text-white uppercase tracking-widest">
<div className="text-center py-3">
<h2 className="text-[12px] font-black text-white uppercase tracking-widest">
{mode === "login" ? "LOGIN" : "REGISTER"}
</h2>
</div>
{/* Form */}
<div className="px-8 pb-6 space-y-4">
<div className="px-4 pb-6 space-y-4">
{/* Phone Number */}
<div>
<label className="block text-[11px] font-semibold text-white/80 mb-1">
Phone Number
</label>
<div className="flex">
<span className="flex items-center justify-center bg-white text-[#333] text-[12px] font-bold px-3 border border-gray-300 whitespace-nowrap select-none">
<span className="flex items-center justify-center bg-white text-[#333] text-[11px] font-bold px-1.5 border border-gray-300 whitespace-nowrap select-none">
ET +251
</span>
<input

View File

@ -8,12 +8,18 @@ import { RightPanel } from "@/components/layout/right-panel"
import { SiteFooter } from "@/components/layout/site-footer"
import { AuthModal } from "@/components/layout/auth-modal"
import { MobileBottomNav } from "@/components/layout/mobile-bottom-nav"
import { cn } from "@/lib/utils"
type AuthMode = "login" | "register"
export default function LayoutClientWrapper({ children }: { children: React.ReactNode }) {
const pathname = usePathname()
const isLivePage = pathname === "/live"
const isVirtualPage = pathname === "/virtual"
const isSpecialGamesPage = pathname === "/special-games"
const hideLeftSidebar = isLivePage || isVirtualPage || isSpecialGamesPage
const hideRightSidebar = isVirtualPage || isSpecialGamesPage // Show RightPanel on Live page
const [authOpen, setAuthOpen] = useState(false)
const [authMode, setAuthMode] = useState<AuthMode>("login")
@ -24,23 +30,25 @@ export default function LayoutClientWrapper({ children }: { children: React.Reac
}, [])
return (
<div className="flex min-h-screen flex-col pb-14 md:pb-0">
<div className="flex min-h-screen flex-col pb-14 md:pb-0 overflow-x-hidden">
<SiteHeader
onLoginClick={() => openAuth("login")}
onRegisterClick={() => openAuth("register")}
/>
<div className="flex w-full flex-1 gap-0">
{/* Sidebar: hidden on mobile */}
{!isLivePage && (
<div className="hidden md:block">
<div className="flex w-full flex-1 gap-0 min-w-0">
{/* Sidebar: hidden on mobile and hidden on specific pages */}
{!hideLeftSidebar && (
<div className="hidden md:block shrink-0">
<SportsSidebar />
</div>
)}
<main className="flex-1 min-w-0 px-2 py-3">{children}</main>
{/* Right panel: hidden on mobile */}
<div className="hidden md:block">
<main className={cn("flex-1 min-w-0 overflow-x-hidden", !hideLeftSidebar && "px-2 py-3")}>{children}</main>
{/* Right panel: completely off-flow on mobile/tablet; only from lg to match RightPanel */}
{!hideRightSidebar && (
<div className="hidden lg:block shrink-0 overflow-hidden">
<RightPanel />
</div>
)}
</div>
<SiteFooter />

View File

@ -3,6 +3,7 @@
import { Betslip } from "@/components/betting/betslip"
import { ReloadTicket } from "@/components/betting/reload-ticket"
import { CheckYourBet } from "@/components/betting/check-your-bet"
import { useBetslipStore } from "@/lib/store/betslip-store"
import { useState } from "react"
import { Button } from "@/components/ui/button"
@ -10,14 +11,15 @@ import { Input } from "@/components/ui/input"
export function RightPanel() {
const [activeTab, setActiveTab] = useState<"betslip" | "myBets">("betslip")
const bets = useBetslipStore((s) => s.bets)
return (
<aside className="hidden lg:flex w-[280px] shrink-0 flex-col gap-0 border-l border-border/30 bg-[#222]">
<aside className="hidden lg:flex w-[280px] shrink-0 flex-col gap-0 border-l border-border/30 bg-brand-surface">
{/* Search Header */}
<div className="p-3 bg-[#1a1a1a] flex items-center justify-between border-b border-border/20">
<div className="p-3 bg-brand-bg flex items-center justify-between border-b border-border/20">
<div className="flex items-center gap-2 text-[12px] font-bold text-white uppercase">
Fast Bet <span className="text-[#ff9800]">QBET</span>
<svg viewBox="0 0 24 24" className="size-4 fill-[#ff9800] ml-1"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
Fast Bet <span className="text-brand-primary">QBET</span>
<svg viewBox="0 0 24 24" className="size-4 fill-brand-primary ml-1"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
</div>
</div>
@ -26,32 +28,28 @@ export function RightPanel() {
<Input
type="text"
placeholder="Event Code"
className="bg-[#333] border border-border/40 px-2 py-1.5 h-auto text-[11px] outline-none text-white focus:border-[#ff9800] rounded-none shadow-none"
className="bg-brand-surface-light border border-border/40 px-2 py-1.5 h-auto text-[11px] outline-none text-white focus:border-brand-primary rounded-none shadow-none"
/>
<div className="bg-[#333] border border-border/40 px-2 py-1.5 text-[11px] text-muted-foreground flex items-center justify-center">...</div>
<div className="bg-brand-surface-light border border-border/40 px-2 py-1.5 text-[11px] text-muted-foreground flex items-center justify-center">...</div>
</div>
{/* Tab switcher */}
<div className="flex items-center justify-between text-[11px] font-bold py-2.5 px-1 border-b border-border/10">
<div className="flex items-center gap-2">
<span className="text-[#ff9800] uppercase cursor-pointer">Betslip</span>
<span className="bg-[#ff9800] text-black px-1.5 rounded-full text-[10px] font-bold">0</span>
<span className="text-brand-primary uppercase cursor-pointer">Betslip</span>
<span className="bg-brand-primary text-black px-1.5 rounded-full text-[10px] font-bold min-w-[18px] text-center">{bets.length}</span>
<Button
variant="ghost"
className="text-white uppercase flex items-center gap-1 ml-2 opacity-80 hover:opacity-100 p-0 h-auto font-bold text-[11px]"
>
<svg viewBox="0 0 24 24" className="size-3 fill-[#ff9800]"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>
<svg viewBox="0 0 24 24" className="size-3 fill-brand-primary"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>
Settings
</Button>
</div>
<span className="text-white uppercase cursor-pointer opacity-80 hover:opacity-100">Decimal</span>
</div>
<div className="py-10 px-4 text-center">
<p className="text-[11px] text-muted-foreground font-medium leading-relaxed">
No bet has been selected. To select a bet, please click on the respective odds
</p>
</div>
<Betslip />
<ReloadTicket />
<CheckYourBet />

View File

@ -4,7 +4,7 @@ import Link from "next/link"
export function SiteFooter() {
return (
<footer className="bg-[#2a2a2a] text-white pt-12">
<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">
{/* ABOUT */}
<div>
@ -51,12 +51,12 @@ export function SiteFooter() {
</div>
{/* Logo Section */}
<div className="flex flex-col items-center justify-center py-16 border-t border-white/5 mt-12 bg-[#222]">
<div className="flex items-center bg-[#1a1a1a] px-5 py-2">
<div className="bg-[#852222] px-3 py-1 -skew-x-12">
<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="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">HARIF</span>
</div>
<span className="text-3xl font-black text-[#ff9800] italic tracking-tighter ml-1">SPORT</span>
<span className="text-3xl font-black text-brand-primary italic tracking-tighter ml-1">SPORT</span>
</div>
{/* Footer Links */}
@ -70,7 +70,7 @@ export function SiteFooter() {
</div>
{/* Cookie Text */}
<div className="bg-[#1a1a1a] py-10 px-6 text-center">
<div className="bg-brand-bg py-10 px-6 text-center">
<div className="container mx-auto max-w-5xl">
<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.

View File

@ -6,13 +6,13 @@ import { useState, useEffect } from "react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import Image from "next/image"
const allNavItems = [
{ href: "/", label: "SPORTS" },
{ href: "/today", label: "TODAY" },
{ href: "/", label: "ALL SPORTS" },
{ href: "/live", label: "LIVE" },
{ href: "/virtual", label: "VIRTUAL" },
{ href: "/special-games", label: "SPECIAL G." },
{ href: "/special-games", label: "SPECIAL Games" },
{ href: "/multi-hot-5", label: "MULTI HOT 5" },
{ href: "/poker", label: "POKER", isNew: true },
{ href: "/race", label: "RACE", isNew: true },
@ -68,7 +68,14 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<div className="hidden md:flex bg-brand-surface px-3 py-1 items-center justify-between text-[11px] text-white">
<div className="flex items-center gap-4">
<button className="flex items-center gap-1.5 hover:text-primary transition-colors">
<img src="https://flagcdn.com/w20/gb.png" width="16" alt="English" className="rounded-sm" />
<Image
src="https://flagcdn.com/w20/gb.png"
alt="English"
width={20}
height={15}
className="rounded-sm"
unoptimized // Since it's an external image from a CDN
/>
<span className="font-bold flex items-center gap-1">en <span className="text-[8px]"></span></span>
</button>
<div className="flex items-center gap-2 font-bold">
@ -78,14 +85,16 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
</div>
<div className="flex items-center gap-6">
<div className="flex items-center gap-3">
<span className="text-white font-bold tracking-tight">+251 (0) Number</span>
<span className="text-white font-bold tracking-tight">+251 (0)
<Input type="password" placeholder="Password" className="bg-brand-surface-light border-none px-2 py-0.5 w-32 text-[11px] h-7 rounded-none shadow-none text-white placeholder:text-gray-500" />
</span>
<Input type="password" placeholder="Password" className="bg-brand-surface-light border-none px-2 py-0.5 w-32 text-[11px] h-7 rounded-none shadow-none text-white placeholder:text-gray-500" />
</div>
<div className="flex items-center gap-1">
<Button onClick={onLoginClick} className="bg-[#e67e22] text-white hover:bg-[#d35400] px-5 h-7 text-[11px] font-bold rounded-none uppercase">
<Button onClick={onLoginClick} className="bg-brand-primary text-white hover:bg-brand-primary-hover px-5 h-7 text-[11px] font-bold rounded-none uppercase">
Login
</Button>
<Button onClick={onRegisterClick} className="bg-[#d35400] text-white hover:bg-[#c0392b] px-5 h-7 text-[11px] font-bold rounded-none uppercase">
<Button onClick={onRegisterClick} className="bg-brand-primary text-white hover:bg-brand-primary-hover px-5 h-7 text-[11px] font-bold rounded-none uppercase">
Sign Up
</Button>
</div>
@ -119,13 +128,13 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<div className="flex items-center gap-1 shrink-0">
<button
onClick={onLoginClick}
className="bg-[#e67e22] text-white px-3 h-8 text-[11px] font-bold uppercase"
className="bg-brand-primary text-white px-3 h-8 text-[11px] font-bold uppercase"
>
LOGIN
</button>
<button
onClick={onRegisterClick}
className="bg-[#d35400] text-white px-3 h-8 text-[11px] font-bold uppercase"
className="bg-brand-primary text-white px-3 h-8 text-[11px] font-bold uppercase"
>
SIGN UP
</button>
@ -133,30 +142,38 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
</div>
{/* ===== DESKTOP: Main header bar ===== */}
<div className="hidden md:flex items-center px-0 bg-[#333] h-[60px]">
<div className="hidden md:flex items-center px-0 bg-brand-bg h-[60px]">
<Link href="/" className="flex items-center shrink-0">
<div className="flex items-center bg-brand-surface h-[60px] px-4">
<div className="flex items-center bg-brand-surface h-[60px] px-4 w-[280px] shrink-0 border-r border-white/5">
<div className="bg-brand-accent px-3 py-1 -skew-x-12 flex items-center h-[34px]">
<span className="text-2xl font-black text-white italic tracking-tighter skew-x-12 inline-block leading-none">HARIF</span>
</div>
<span className="text-2xl font-black text-brand-primary italic tracking-tighter ml-1 leading-none">SPORT</span>
</div>
</Link>
<div className="flex items-center flex-1 justify-end px-4 h-full gap-0">
<Link href="/" className="flex items-center justify-center bg-brand-primary h-[60px] w-[50px] shrink-0 hover:bg-brand-primary-hover transition-colors">
<svg viewBox="0 0 24 24" className="size-6 fill-black"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
<div className="flex items-center flex-1 justify-end px-4 h-full gap-0 bg-brand-surface">
<Link
href="/"
className={cn(
"flex items-center justify-center h-[60px] w-[50px] shrink-0 transition-colors",
pathname === "/"
? "bg-brand-primary hover:bg-brand-primary-hover"
: "text-white hover:bg-white/10"
)}
>
<svg viewBox="0 0 24 24" className={cn("size-6", pathname === "/" ? "fill-black" : "fill-white")}><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
</Link>
<nav className="flex items-center text-[10.5px] font-bold h-full">
{allNavItems.slice(0, 5).map((item) => {
const isActive = pathname === item.href
const isActive = pathname === item.href && item.href !== "/"
return (
<Link key={item.href} href={item.href}
className={cn(
"px-4 flex items-center h-full transition-colors uppercase",
isActive ? (item.label === "LIVE" ? "bg-brand-primary text-black" : "text-primary bg-black/10") : "text-white hover:text-primary"
"px-4 flex items-center h-full transition-colors uppercase relative",
isActive ? "text-white bg-brand-primary" : "text-white hover:bg-white/5"
)}
>
{item.label}
<span>{item.label}</span>
</Link>
)
})}
@ -168,11 +185,11 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
<Link key={item.href} href={item.href}
className={cn(
"px-4 flex flex-col items-center justify-center h-full transition-colors relative uppercase",
isActive ? "text-primary bg-black/10" : "text-white hover:text-primary"
isActive ? "text-white bg-brand-primary" : "text-white hover:bg-white/5"
)}
>
{item.isNew && (
<span className="absolute top-3 text-[7px] text-primary font-black tracking-tighter leading-none">NEW</span>
<span className="absolute top-3 text-[7px] text-white/70 font-black tracking-tighter leading-none">NEW</span>
)}
<span className={cn(item.isNew && "mt-1.5")}>{item.label}</span>
</Link>
@ -184,8 +201,14 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
{/* ===== MOBILE: Horizontally scrollable nav tabs ===== */}
<div className="flex md:hidden overflow-x-auto scrollbar-none bg-brand-surface-light border-t border-white/5">
<Link href="/" className="flex-none px-4 h-9 flex items-center bg-brand-primary">
<svg viewBox="0 0 24 24" className="size-5 fill-black"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
<Link
href="/"
className={cn(
"flex-none px-4 h-9 flex items-center transition-colors",
pathname === "/" ? "bg-brand-primary" : "text-white"
)}
>
<svg viewBox="0 0 24 24" className={cn("size-5", pathname === "/" ? "fill-black" : "fill-white")}><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>
</Link>
{allNavItems.map((item) => {
const isActive = pathname === item.href
@ -210,7 +233,7 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
</div>
{/* ===== MOBILE: Sport Category Icons Row ===== */}
<div className="flex md:hidden overflow-x-auto scrollbar-none bg-[#333] border-t border-white/5 py-2 px-2 gap-4">
<div className="flex md:hidden overflow-x-auto scrollbar-none bg-brand-surface-light border-t border-white/5 py-2 px-2 gap-4">
{[
{ label: "Check Bet", icon: (active: boolean) => <svg viewBox="0 0 24 24" className="size-5 fill-white/80"><path d="M20 4H4c-1.11 0-2 .89-2 2v12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"/></svg>, count: 99 },
{ label: "Live", icon: (active: boolean) => <div className="size-2 bg-brand-live rounded-full animate-pulse" />, count: 1247 },
@ -229,11 +252,11 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
</div>
{/* ===== DESKTOP: Secondary sub-header ===== */}
{pathname !== "/virtual" && pathname !== "/special-games" && (
<div className="hidden md:flex bg-brand-surface-light border-t border-white/5 h-8 px-3 items-center gap-6 text-[11px]">
{[
{ label: "Sport Home", href: "/" },
{ label: "General View", href: "/live", forceActive: isLivePage },
{ label: "Event View", href: "/live/event" },
{ label: "Live View", href: "/live", forceActive: isLivePage },
].map((tab) => {
const isActive = tab.forceActive || pathname === tab.href
return (
@ -251,6 +274,7 @@ export function SiteHeader({ onLoginClick, onRegisterClick }: SiteHeaderProps) {
)
})}
</div>
)}
</header>
{/* ===== MOBILE Drawer ===== */}

View File

@ -5,6 +5,18 @@ import Link from "next/link"
import { popularLeagues } from "@/lib/mock-data"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { ChevronsLeft } from "lucide-react"
/** Soccer ball icon - outline style for white/green theme */
function SoccerBallIcon({ className }: { className?: string }) {
return (
<svg viewBox="0 0 24 24" className={className} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M12 2v20M2 12h20" />
<path d="M4.93 4.93l14.14 14.14M4.93 19.07l14.14-14.14" strokeWidth="1" />
</svg>
)
}
const sportCategories = [
{ id: "football", name: "Football", icon: "⚽", count: 1412 },
@ -25,11 +37,13 @@ export function SportsSidebar() {
const [activeSport, setActiveSport] = useState("football")
return (
<aside className="hidden h-full w-[240px] 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">
{/* Sports Menu Header */}
<div className="bg-brand-surface px-3 py-2 text-[11px] font-black text-brand-primary 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 className="bg-brand-surface px-3 py-2 text-[11px] font-black text-white uppercase tracking-tighter flex items-center justify-between border-b border-border/30 h-10">
<span>Sports Menu</span>
<button type="button" className="p-1 rounded hover:bg-white/10 text-white/70 hover:text-white transition-colors" aria-label="Collapse sidebar">
<ChevronsLeft className="size-4" />
</button>
</div>
{/* Top Leagues Header */}
@ -45,27 +59,28 @@ export function SportsSidebar() {
href={`/?league=${league.id}`}
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.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">
<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">
{league.logo ? (
<img src={league.logo} alt="" className="size-full object-contain" />
) : (
<span className="text-[10px] leading-none invert"></span>
<span className="text-[11px]"></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-brand-primary transition-colors shrink-0">
<div className="size-1.5 bg-white/40 rounded-full group-hover:bg-brand-primary" />
<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>
</div>
<SoccerBallIcon className="size-4 shrink-0 text-white/40 group-hover:text-brand-primary transition-colors" />
</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>
<Button asChild 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]">
<Link href="/live">
<span className="size-2 rounded-full bg-brand-primary mr-2 live-dot shadow-[0_0_8px_var(--brand-primary)]"></span>
IN-PLAY
</Link>
</Button>
{/* Quick Filter Section */}
@ -75,7 +90,7 @@ export function SportsSidebar() {
{["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 === "All" ? "bg-brand-surface-light text-white" : "bg-brand-surface text-white/50 hover:text-white"
)}>{t}</button>
))}
</div>
@ -112,7 +127,7 @@ export function SportsSidebar() {
</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>
<SoccerBallIcon className="size-3.5 text-white/30 shrink-0" />
</div>
</button>
))}
@ -123,17 +138,49 @@ export function SportsSidebar() {
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-brand-surface group">
<Button
variant="ghost"
type="button"
className="flex flex-col items-center justify-center py-4 h-auto rounded-none border-r border-border/10 hover:bg-brand-surface group"
onClick={() => {
const w = 1200
const h = 800
const left = typeof window !== "undefined" ? Math.max(0, (window.screen.width - w) / 2) : 0
const top = typeof window !== "undefined" ? Math.max(0, (window.screen.height - h) / 2) : 0
window.open(
"https://s5.sir.sportradar.com/betinaction/en",
"LiveScore",
`noopener,noreferrer,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`
)
}}
>
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-brand-primary 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-brand-surface group">
<Button
variant="ghost"
type="button"
className="flex flex-col items-center justify-center py-4 h-auto rounded-none border-r border-border/10 hover:bg-brand-surface group"
onClick={() => {
const w = 1200
const h = 800
const left = typeof window !== "undefined" ? Math.max(0, (window.screen.width - w) / 2) : 0
const top = typeof window !== "undefined" ? Math.max(0, (window.screen.height - h) / 2) : 0
window.open(
"https://statistics.betconstruct.com/#/en",
"Results",
`noopener,noreferrer,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`
)
}}
>
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-brand-primary 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-brand-surface group">
<Button variant="ghost" asChild className="flex flex-col items-center justify-center py-4 h-auto rounded-none hover:bg-brand-surface group">
<Link href="/print-odds" className="flex flex-col items-center justify-center">
<svg viewBox="0 0 24 24" className="size-5 mb-1.5 fill-muted-foreground group-hover:fill-brand-primary 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>
</Link>
</Button>
</div>

View File

@ -19,11 +19,11 @@ const buttonVariants = cva(
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
"hs-primary": "bg-[#ff9800] text-black font-bold hover:bg-[#ffa726] rounded-none",
"hs-secondary": "bg-[#333] text-white hover:bg-[#444] border border-border/20 rounded-none",
"hs-maroon": "bg-[#852222] text-white font-bold hover:bg-[#962d2d] rounded-none",
"hs-inplay": "bg-[#004242] text-[#ff9800] font-bold hover:bg-[#005252] border-y border-border/10 rounded-none",
"hs-nav": "bg-[#1a1a1a] text-[#ff9800] font-bold hover:bg-[#222] border-r border-border/10 rounded-none",
"hs-primary": "bg-brand-primary text-black font-bold hover:bg-brand-primary-hover rounded-none",
"hs-secondary": "bg-brand-surface-light text-white hover:bg-[#404040] border border-border/20 rounded-none",
"hs-maroon": "bg-brand-accent text-white font-bold hover:opacity-90 rounded-none",
"hs-inplay": "bg-[#004242] text-brand-primary font-bold hover:bg-[#005252] border-y border-border/10 rounded-none",
"hs-nav": "bg-brand-bg text-brand-primary font-bold hover:bg-brand-surface border-r border-border/10 rounded-none",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",

View File

@ -1,10 +1,10 @@
"use client"
"use client";
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Tabs as TabsPrimitive } from "radix-ui"
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { Tabs as TabsPrimitive } from "radix-ui";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Tabs({
className,
@ -18,29 +18,30 @@ function Tabs({
orientation={orientation}
className={cn(
"group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
className
className,
)}
{...props}
/>
)
);
}
const tabsListVariants = cva(
"rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none data-[variant=hs-home]:rounded-none data-[variant=hs-home]:bg-[#1a1a1a] data-[variant=hs-nav]:rounded-none data-[variant=hs-nav]:bg-[#1a1a1a] group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
"rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none data-[variant=hs-home]:rounded-none data-[variant=hs-home]:bg-brand-bg data-[variant=hs-nav]:rounded-none data-[variant=hs-nav]:bg-brand-bg group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
{
variants: {
variant: {
default: "bg-muted",
line: "gap-1 bg-transparent",
"hs-home": "w-full gap-0 border border-border/20",
"hs-nav": "w-full gap-0 border border-border/20 overflow-x-auto justify-start",
"hs-nav":
"w-full gap-0 border border-border/20 flex-wrap justify-start overflow-hidden min-h-14 h-auto py-1",
},
},
defaultVariants: {
variant: "default",
},
}
)
},
);
function TabsList({
className,
@ -55,7 +56,7 @@ function TabsList({
className={cn(tabsListVariants({ variant }), className)}
{...props}
/>
)
);
}
function TabsTrigger({
@ -69,14 +70,14 @@ function TabsTrigger({
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
"group-data-[variant=hs-home]/tabs-list:rounded-none group-data-[variant=hs-home]/tabs-list:h-12 group-data-[variant=hs-home]/tabs-list:text-[13px] group-data-[variant=hs-home]/tabs-list:font-extrabold group-data-[variant=hs-home]/tabs-list:uppercase group-data-[variant=hs-home]/tabs-list:data-[state=active]:bg-transparent group-data-[variant=hs-home]/tabs-list:data-[state=active]:text-white",
"group-data-[variant=hs-nav]/tabs-list:rounded-none group-data-[variant=hs-nav]/tabs-list:flex-col group-data-[variant=hs-nav]/tabs-list:min-w-[70px] group-data-[variant=hs-nav]/tabs-list:py-2 group-data-[variant=hs-nav]/tabs-list:gap-1 group-data-[variant=hs-nav]/tabs-list:border-r group-data-[variant=hs-nav]/tabs-list:border-border/10 group-data-[variant=hs-nav]/tabs-list:data-[state=active]:bg-[#222]",
"group-data-[variant=hs-nav]/tabs-list:rounded-none group-data-[variant=hs-nav]/tabs-list:flex-col group-data-[variant=hs-nav]/tabs-list:min-w-[70px] group-data-[variant=hs-nav]/tabs-list:py-2 group-data-[variant=hs-nav]/tabs-list:gap-1 group-data-[variant=hs-nav]/tabs-list:border-r group-data-[variant=hs-nav]/tabs-list:border-border/10 group-data-[variant=hs-nav]/tabs-list:data-[state=active]:bg-brand-surface",
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
"after:bg-[#ff9800] after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-0 group-data-[orientation=horizontal]/tabs:after:h-[3px] group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100 group-data-[variant=hs-home]/tabs-list:data-[state=active]:after:opacity-100",
className
"after:bg-brand-primary after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-0 group-data-[orientation=horizontal]/tabs:after:h-[3px] group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100 group-data-[variant=hs-home]/tabs-list:data-[state=active]:after:opacity-100",
className,
)}
{...props}
/>
)
);
}
function TabsContent({
@ -89,7 +90,7 @@ function TabsContent({
className={cn("flex-1 outline-none", className)}
{...props}
/>
)
);
}
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };