botWebWars/frontend/src/components/PlayerList.tsx

140 lines
5.5 KiB
TypeScript
Raw Normal View History

import React from 'react';
2026-09-05 21:20:39 +00:00
import type { BoardState, Player } from '../types';
interface PlayerListProps {
2026-09-05 21:20:39 +00:00
boardState: BoardState;
selectedPlayer: Player | null;
onSelectPlayer: (player: Player) => void;
onRemovePlayer: (id: string) => void;
}
export const PlayerList: React.FC<PlayerListProps> = ({
2026-09-05 21:20:39 +00:00
boardState,
selectedPlayer,
onSelectPlayer,
onRemovePlayer,
}) => {
2026-09-05 21:20:39 +00:00
const { players, turn } = boardState;
const currentTurnId = turn.current_player_id;
return (
<div className="flex flex-col h-full bg-slate-900 border-l border-slate-800 w-80">
{/* Header */}
<div className="p-4 border-b border-slate-800 flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="w-2.5 h-2.5 rounded-full bg-sky-400" />
<h3 className="font-semibold text-slate-100 text-sm">Active Bots</h3>
</div>
<span className="text-xs font-mono px-2 py-0.5 rounded-full bg-slate-800 text-slate-300 border border-slate-700">
{players.length} / 4096
</span>
</div>
2026-09-05 21:20:39 +00:00
{/* Turn Info Banner */}
{players.length > 0 && (
<div className="px-4 py-2.5 bg-slate-950/70 border-b border-slate-800/80 flex items-center justify-between text-xs font-mono">
<span className="text-slate-400">
Round <strong className="text-sky-400">{turn.round_number}</strong>
</span>
<span className="text-slate-400">
Turn <strong className="text-amber-400">#{turn.turn_number}</strong>
</span>
</div>
)}
{/* Players List */}
<div className="flex-1 overflow-y-auto p-3 space-y-2">
{players.length === 0 ? (
<div className="text-center py-12 px-4 text-slate-500 text-xs">
<div className="text-2xl mb-2">🤖</div>
No players registered yet.
<br />
2026-09-05 21:20:39 +00:00
Register a player or spawn a random bot to start taking turns!
</div>
) : (
players.map((player) => {
const isSelected = selectedPlayer?.id === player.id;
2026-09-05 21:20:39 +00:00
const isCurrentTurn = currentTurnId === player.id;
const orderIndex = turn.turn_order.indexOf(player.id);
return (
<div
key={player.id}
onClick={() => onSelectPlayer(player)}
className={`group flex items-center justify-between p-2.5 rounded-xl border transition-all cursor-pointer ${
2026-09-05 21:20:39 +00:00
isCurrentTurn
? 'bg-amber-950/25 border-amber-500/70 shadow-md shadow-amber-500/10'
: isSelected
? 'bg-sky-950/40 border-sky-500 shadow-md shadow-sky-500/10'
: 'bg-slate-950/60 border-slate-800 hover:border-slate-700 hover:bg-slate-800/40'
}`}
>
<div className="flex items-center gap-3 min-w-0">
2026-09-05 21:20:39 +00:00
<div className="relative">
<div
className="w-8 h-8 rounded-full flex-shrink-0 flex items-center justify-center text-white font-bold text-xs shadow"
style={{
backgroundColor: player.color,
boxShadow: isCurrentTurn
? '0 0 14px #f59e0b'
: `0 0 10px ${player.color}55`,
}}
>
{player.name.slice(0, 2).toUpperCase()}
</div>
{isCurrentTurn && (
<span className="absolute -top-1.5 -right-1 text-[11px] leading-none">
👑
</span>
)}
</div>
2026-09-05 21:20:39 +00:00
<div className="min-w-0">
2026-09-05 21:20:39 +00:00
<div className="flex items-center gap-1.5">
<span className="text-xs font-semibold text-slate-200 truncate">
{player.name}
</span>
{orderIndex !== -1 && (
<span className="text-[10px] font-mono text-slate-500">
#{orderIndex + 1}
</span>
)}
</div>
<div className="text-[11px] font-mono text-slate-400">
pos: <span className="text-emerald-400">({player.x}, {player.y})</span>
2026-09-05 21:20:39 +00:00
{isCurrentTurn && (
<span className="ml-1.5 text-amber-400 font-bold text-[10px]">
TURN
</span>
)}
</div>
</div>
</div>
<div className="flex items-center gap-1.5 opacity-60 group-hover:opacity-100 transition-opacity">
<button
onClick={(e) => {
e.stopPropagation();
onRemovePlayer(player.id);
}}
title="Remove Bot"
className="p-1 rounded text-slate-500 hover:text-red-400 hover:bg-red-950/40 transition-colors text-xs"
>
</button>
</div>
</div>
);
})
)}
</div>
{/* Footer Info */}
<div className="p-3 border-t border-slate-800 bg-slate-950/40 text-[11px] font-mono text-slate-400 flex justify-between items-center">
<span>Coordinate range:</span>
<span className="text-sky-400 font-semibold">[0,0] [64,64]</span>
</div>
</div>
);
};