Spaces:
Runtime error
Runtime error
File size: 4,475 Bytes
e4d7d50 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | /**
* ChessBoard component — live chess board with piece animations
* Design: Quantitative Finance Dark — cream/brown squares, high-contrast pieces
*
* White pieces: bright white (#FFFFFF) with thick dark stroke — visible on ALL squares
* Black pieces: vivid gold (#FFD700) with dark shadow — visible on ALL squares
* Layout: fully self-contained, no overflow, stable position
*/
import { PIECES, type GameState } from "@/lib/simulation";
interface ChessBoardProps {
state: GameState;
}
const LIGHT_SQ = "#F0D9B5";
const DARK_SQ = "#B58863";
const FILES = ["a","b","c","d","e","f","g","h"];
const RANKS = ["8","7","6","5","4","3","2","1"];
export default function ChessBoard({ state }: ChessBoardProps) {
return (
<div style={{ width: "100%", height: "100%", display: "flex", flexDirection: "column" }}>
{/* Board + rank labels row */}
<div style={{ flex: 1, display: "flex", minHeight: 0 }}>
{/* Rank labels */}
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-around", width: "14px", flexShrink: 0, paddingBottom: "14px" }}>
{RANKS.map((r) => (
<span key={r} style={{
fontFamily: "IBM Plex Mono, monospace",
fontSize: "9px",
fontWeight: 600,
color: "rgba(255,255,255,0.55)",
textAlign: "center",
lineHeight: 1,
}}>
{r}
</span>
))}
</div>
{/* Board + file labels column */}
<div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }}>
{/* Board grid */}
<div style={{
flex: 1,
display: "grid",
gridTemplateColumns: "repeat(8, 1fr)",
gridTemplateRows: "repeat(8, 1fr)",
border: "1px solid rgba(255,255,255,0.15)",
borderRadius: "2px",
overflow: "hidden",
minHeight: 0,
}}>
{state.board.map((row, rankIdx) =>
row.map((piece, fileIdx) => {
const isLight = (rankIdx + fileIdx) % 2 === 0;
const isWhitePiece = piece !== null && piece === piece.toUpperCase();
return (
<div
key={`${rankIdx}-${fileIdx}`}
style={{
background: isLight ? LIGHT_SQ : DARK_SQ,
display: "flex",
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
}}
>
{piece && (
<span
style={{
fontSize: "clamp(14px, 2.5vw, 28px)",
lineHeight: 1,
userSelect: "none",
// White pieces use hollow Unicode symbols (♔♕♖♗♘♙)
// Rendered in dark navy so the outline is visible on BOTH cream and brown squares
// Black pieces use filled Unicode symbols (♚♛♜♝♞♟) in vivid gold
color: isWhitePiece ? "#1a2744" : "#E8B400",
textShadow: isWhitePiece
? "0 1px 2px rgba(255,255,255,0.5)"
: "0 1px 3px rgba(0,0,0,0.9), 0 0 8px rgba(232,180,0,0.5)",
filter: isWhitePiece
? "drop-shadow(0 0 1px rgba(255,255,255,0.4))"
: "drop-shadow(0 0 3px rgba(232,180,0,0.6))",
}}
>
{PIECES[piece] ?? piece}
</span>
)}
</div>
);
})
)}
</div>
{/* File labels */}
<div style={{ display: "flex", height: "14px", flexShrink: 0 }}>
{FILES.map((f) => (
<span key={f} style={{
flex: 1,
textAlign: "center",
fontFamily: "IBM Plex Mono, monospace",
fontSize: "9px",
fontWeight: 600,
color: "rgba(255,255,255,0.55)",
lineHeight: "14px",
}}>
{f}
</span>
))}
</div>
</div>
</div>
</div>
);
}
|