diff --git a/panel/src/games/GameLobby.tsx b/panel/src/games/GameLobby.tsx index a4ea7a3..91e4fe7 100644 --- a/panel/src/games/GameLobby.tsx +++ b/panel/src/games/GameLobby.tsx @@ -1,10 +1,26 @@ -import { useState, useEffect } from "react"; +import type { ReactNode } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; +import { + ArrowRight, + ChevronLeft, + Clock3, + Coins, + Eye, + Gamepad2, + Sparkles, + Swords, + Users, +} from "lucide-react"; +import { cn } from "../lib/utils"; import { useWebSocket } from "../lib/useWebSocket"; import { gameUIRegistry } from "./registry"; -import { ChevronLeft } from "lucide-react"; +import { + CHESS_TIME_CONTROLS, + CHESS_TIME_CONTROL_CATEGORIES, + CHESS_TIME_CONTROL_LABELS, +} from "./chess/timeControls"; -// Mirrors RoomSummary in api/src/games/types.ts โ keep in sync interface RoomSummary { id: string; gameSlug: string; @@ -17,18 +33,409 @@ interface RoomSummary { betAmount: number; } -const CHESS_TIME_CONTROLS = [ - { key: "bullet_1_0", label: "1+0", category: "Bullet" }, - { key: "bullet_2_1", label: "2+1", category: "Bullet" }, - { key: "blitz_3_0", label: "3+0", category: "Blitz" }, - { key: "blitz_3_2", label: "3+2", category: "Blitz" }, - { key: "blitz_5_0", label: "5+0", category: "Blitz" }, - { key: "blitz_5_3", label: "5+3", category: "Blitz" }, - { key: "rapid_10_0", label: "10+0", category: "Rapid" }, - { key: "rapid_15_10", label: "15+10", category: "Rapid" }, - { key: "classical_30_0", label: "30+0", category: "Classical" }, - { key: "none", label: "None", category: "No Clock" }, -] as const; +type ConfiguredGame = "chess" | "blackjack" | null; + +const BET_OPTIONS = [0, 10, 25, 50, 100, 250, 500] as const; + +function roomStatusMeta(status: RoomSummary["status"]) { + if (status === "waiting") { + return { + label: "Waiting", + chipClassName: "border-warning/25 bg-warning/12 text-warning", + accentClassName: "from-warning/18 via-warning/8 to-transparent", + }; + } + if (status === "playing") { + return { + label: "In Progress", + chipClassName: "border-success/25 bg-success/12 text-success", + accentClassName: "from-success/18 via-success/8 to-transparent", + }; + } + return { + label: "Finished", + chipClassName: "border-border/70 bg-card/80 text-text-tertiary", + accentClassName: "from-white/8 via-transparent to-transparent", + }; +} + +function gameSurfaceClass(slug: string): string { + return slug === "blackjack" + ? "border-emerald-500/20 bg-[radial-gradient(circle_at_top,rgba(34,197,94,0.14),transparent_40%),linear-gradient(180deg,rgba(6,95,70,0.45),rgba(6,78,59,0.12))]" + : "border-primary/20 bg-[radial-gradient(circle_at_top,rgba(233,195,73,0.14),transparent_40%),linear-gradient(180deg,rgba(61,46,0,0.35),rgba(61,46,0,0.08))]"; +} + +function roomActionLabel(room: RoomSummary): string { + return room.status === "waiting" ? "Join Room" : "Spectate"; +} + +function orderRooms(a: RoomSummary, b: RoomSummary): number { + const statusWeight = { waiting: 0, playing: 1, finished: 2 } as const; + return statusWeight[a.status] - statusWeight[b.status] + || b.playerCount - a.playerCount + || b.spectatorCount - a.spectatorCount; +} + +function MetricCard({ label, value, hint }: { label: string; value: string; hint: string }) { + return ( +
{selectedGame.description}
++ Pick the table or duel you want to host, then tune the settings before you publish the invite link. +
+Browse and create game rooms
-+ The lobby now separates waiting rooms from active tables, exposes launch rules up front, and makes room creation feel like one guided flow instead of a stack of toggles. +
-+ Create a new room to seed the lobby, or switch filters if you expected another game type. +
+ +Beat the dealer โ closest to 21 wins
- - {/* Bet Amount */} -Choose your time control
- -{body}
+ +The game type "{gameSlug}" doesn't exist.
- -This room no longer exists or has expired.
- -- {preferAs === "spectator" ? "Joining as spectator..." : "Joining room..."} -
-- You opened this game in another tab. Actions from this tab are disabled. -
+{plugin.description}
++ {plugin.manualStart + ? "Hosts can keep collecting players and spectators, then start the table manually." + : "The game will start automatically as soon as every required player seat is occupied."} +
+