anycoder-087d6747 / components /ChessBoard.js
johnreaver's picture
Upload components/ChessBoard.js with huggingface_hub
9ac3b1c verified
import { motion } from 'framer-motion';
export default function ChessBoard({ board, onSquareClick, selectedPos, validMoves, lastMove, turn }) {
const files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const ranks = ['8', '7', '6', '5', '4', '3', '2', '1'];
return (
<div className="relative">
{/* Board Border Decoration */}
<div className="absolute -inset-4 bg-black z-0 hidden sm:block" />
<div className="grid grid-cols-8 grid-rows-8 border-4 border-black bg-black gap-0 relative z-10 shadow-piece">
{board.map((row, rowIndex) => (
row.map((piece, colIndex) => {
const isBlackSquare = (rowIndex + colIndex) % 2 === 1;
const isSelected = selectedPos?.r === rowIndex && selectedPos?.c === colIndex;
const isValidMove = validMoves.some(m => m.r === rowIndex && m.c === colIndex);
const isLastMoveFrom = lastMove?.from.r === rowIndex && lastMove?.from.c === colIndex;
const isLastMoveTo = lastMove?.to.r === rowIndex && lastMove?.to.c === colIndex;
const isCheck = false; // Simplified for this demo
return (
<div
key={`${rowIndex}-${colIndex}`}
onClick={() => onSquareClick(rowIndex, colIndex)}
className={`
chess-square
${isBlackSquare ? 'bg-[#769656]' : 'bg-[#eeeed2]'}
${isSelected ? '!bg-comic-yellow ring-4 ring-inset ring-black z-20' : ''}
${(isLastMoveFrom || isLastMoveTo) && !isSelected ? 'bg-comic-blue/40' : ''}
`}
>
{/* Coordinate Labels */}
{colIndex === 0 && (
<span className={`absolute top-0.5 left-1 text-[10px] font-bold ${isBlackSquare ? 'text-[#eeeed2]' : 'text-[#769656]'}`}>
{ranks[rowIndex]}
</span>
)}
{rowIndex === 7 && (
<span className={`absolute bottom-0 right-1 text-[10px] font-bold ${isBlackSquare ? 'text-[#eeeed2]' : 'text-[#769656]'}`}>
{files[colIndex]}
</span>
)}
{/* Valid Move Indicator */}
{isValidMove && !piece && (
<div className="w-4 h-4 rounded-full bg-black/20" />
)}
{isValidMove && piece && (
<div className="absolute inset-0 ring-4 ring-inset ring-comic-red/50 rounded-none" />
)}
{/* Piece */}
{piece && (
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
className={`
piece-3d
${isWhitePiece(piece) ? 'text-white drop-shadow-[2px_2px_0_rgba(0,0,0,1)]' : 'text-black drop-shadow-[1px_1px_0_rgba(255,255,255,0.5)]'}
${turn === 'white' && isWhitePiece(piece) ? 'cursor-grab active:cursor-grabbing' : ''}
${turn === 'black' && isBlackPiece(piece) ? 'cursor-grab active:cursor-grabbing' : ''}
`}
style={{
filter: isWhitePiece(piece)
? 'drop-shadow(2px 4px 6px rgba(0,0,0,0.4))'
: 'drop-shadow(2px 4px 6px rgba(0,0,0,0.2))'
>
{getPieceSymbol(piece)}
</motion.div>
)}
</div>
);
})
))}
</div>
</div>
);
}
const isWhitePiece = (p) => p === p.toUpperCase();
const isBlackPiece = (p) => p === p.toLowerCase();
const getPieceSymbol = (p) => {
const map = {
'K': 'β™”', 'Q': 'β™•', 'R': 'β™–', 'B': 'β™—', 'N': 'β™˜', 'P': 'β™™',
'k': 'β™š', 'q': 'β™›', 'r': 'β™œ', 'b': '♝', 'n': 'β™ž', 'p': 'β™Ÿ',
};
return map[p] || '';
};