146 lines
5.8 KiB
TypeScript
146 lines
5.8 KiB
TypeScript
import React from 'react';
|
||
|
||
interface HeaderProps {
|
||
isConnected: boolean;
|
||
gameStarted: boolean;
|
||
onStartGame: () => void;
|
||
onOpenRegister: () => void;
|
||
onQuickSpawn: () => void;
|
||
onResetBoard: () => void;
|
||
playerCount: number;
|
||
isConcluded?: boolean;
|
||
onOpenScoreboard?: () => void;
|
||
}
|
||
|
||
export const Header: React.FC<HeaderProps> = ({
|
||
isConnected,
|
||
gameStarted,
|
||
onStartGame,
|
||
onOpenRegister,
|
||
onQuickSpawn,
|
||
onResetBoard,
|
||
playerCount,
|
||
isConcluded,
|
||
onOpenScoreboard,
|
||
}) => {
|
||
return (
|
||
<header className="h-16 border-b border-slate-800 bg-slate-900/90 backdrop-blur px-6 flex items-center justify-between z-10">
|
||
{/* Brand & Stats */}
|
||
<div className="flex items-center gap-6">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-8 h-8 rounded-lg bg-gradient-to-tr from-sky-500 to-indigo-600 flex items-center justify-center font-black text-white text-base shadow-lg shadow-sky-500/20">
|
||
W
|
||
</div>
|
||
<div>
|
||
<h1 className="text-base font-bold tracking-tight text-white flex items-center gap-2">
|
||
botWebWars
|
||
<span className="text-[10px] uppercase font-mono px-1.5 py-0.5 rounded bg-sky-950 text-sky-400 border border-sky-800">
|
||
v{import.meta.env.VITE_APP_VERSION || '1.3'}
|
||
</span>
|
||
</h1>
|
||
<p className="text-[11px] text-slate-400 font-mono">
|
||
64×64 Grid Arena • Coords (0,0) to (64,64)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Live status badge */}
|
||
<div className="flex items-center gap-2 px-2.5 py-1 rounded-full bg-slate-800 border border-slate-700 text-xs font-mono">
|
||
<span
|
||
className={`w-2 h-2 rounded-full ${
|
||
isConnected ? 'bg-emerald-400 shadow-[0_0_8px_#34d399]' : 'bg-amber-400 animate-ping'
|
||
}`}
|
||
/>
|
||
<span className={isConnected ? 'text-slate-300' : 'text-amber-300'}>
|
||
{isConnected ? 'LIVE SYNC' : 'CONNECTING...'}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Game Phase Badge */}
|
||
{!isConcluded && (
|
||
<div className="flex items-center gap-1.5 px-3 py-1 rounded-full bg-slate-800 border border-slate-700 text-xs font-mono">
|
||
{gameStarted ? (
|
||
<span className="flex items-center gap-1.5 text-emerald-400 font-semibold">
|
||
<span className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse" />
|
||
GAME IN PROGRESS
|
||
</span>
|
||
) : (
|
||
<span className="flex items-center gap-1.5 text-amber-300 font-medium">
|
||
<span className="w-2 h-2 rounded-full bg-amber-400 animate-ping" />
|
||
LOBBY (WAITING TO START)
|
||
</span>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* Game concluded banner tag */}
|
||
{isConcluded && (
|
||
<div className="flex items-center gap-1.5 px-3 py-1 rounded-full bg-amber-500/20 border border-amber-400 text-amber-300 text-xs font-bold animate-pulse">
|
||
<span>🏆</span> GAME CONCLUDED
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Action Buttons */}
|
||
<div className="flex items-center gap-3">
|
||
{/* Start Game Button (Visible during Lobby) */}
|
||
{!gameStarted && !isConcluded && (
|
||
<button
|
||
onClick={onStartGame}
|
||
disabled={playerCount === 0}
|
||
className={`text-xs font-bold px-4 py-1.5 rounded-lg flex items-center gap-1.5 shadow-lg transition-all ${
|
||
playerCount > 0
|
||
? 'bg-gradient-to-r from-emerald-500 to-teal-600 hover:from-emerald-400 hover:to-teal-500 text-white shadow-emerald-500/30 animate-pulse cursor-pointer ring-1 ring-emerald-400'
|
||
: 'bg-slate-800 text-slate-500 border border-slate-700 cursor-not-allowed'
|
||
}`}
|
||
title={playerCount === 0 ? 'Spawn or register bots before starting' : 'Start the game!'}
|
||
>
|
||
<span>▶</span> Start Game ({playerCount} {playerCount === 1 ? 'Bot' : 'Bots'})
|
||
</button>
|
||
)}
|
||
|
||
{isConcluded && onOpenScoreboard && (
|
||
<button
|
||
onClick={onOpenScoreboard}
|
||
className="text-xs font-bold text-amber-950 px-3.5 py-1.5 rounded-lg bg-gradient-to-r from-amber-400 to-yellow-300 hover:from-amber-300 hover:to-yellow-200 shadow-lg shadow-amber-400/30 flex items-center gap-1.5 transition-all"
|
||
>
|
||
<span>🏆</span> Final Scoreboard
|
||
</button>
|
||
)}
|
||
|
||
<a
|
||
href="/docs"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="text-xs font-mono text-slate-400 hover:text-sky-400 transition-colors px-2.5 py-1.5 rounded-lg border border-slate-800 hover:border-slate-700 bg-slate-950/40"
|
||
title="Open FastAPI Swagger API Docs"
|
||
>
|
||
API Docs ↗
|
||
</a>
|
||
|
||
<button
|
||
onClick={onResetBoard}
|
||
className="text-xs font-medium text-slate-400 hover:text-red-400 transition-colors px-3 py-1.5 rounded-lg border border-slate-800 hover:border-red-900/60 bg-slate-950/40"
|
||
title="Regenerate map terrain and clear all players"
|
||
>
|
||
Recreate Layout
|
||
</button>
|
||
|
||
<button
|
||
onClick={onQuickSpawn}
|
||
className="text-xs font-medium text-slate-200 hover:text-white transition-all px-3.5 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 shadow flex items-center gap-1.5"
|
||
>
|
||
<span>🎲</span> Quick Spawn Bot
|
||
</button>
|
||
|
||
<button
|
||
onClick={onOpenRegister}
|
||
className="text-xs font-semibold text-white transition-all px-4 py-1.5 rounded-lg bg-gradient-to-r from-sky-500 to-indigo-600 hover:from-sky-400 hover:to-indigo-500 shadow-lg shadow-sky-500/25 flex items-center gap-1.5"
|
||
>
|
||
<span>+</span> Register Player
|
||
</button>
|
||
</div>
|
||
</header>
|
||
);
|
||
};
|