@@ -6,42 +6,30 @@ import { cn } from "../../lib/utils";
66import PieceIcon from "./PieceIcon" ;
77import { Square } from "chess.js" ;
88
9- const files = [ "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h" ] ;
10- const ranks = [ 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] ;
9+ const defaultFiles = [ "a" , "b" , "c" , "d" , "e" , "f" , "g" , "h" ] ;
10+ const defaultRanks = [ 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] ;
1111
1212function fenToBoard ( fen : string ) : Record < string , string | null > {
1313 const fenBoard = fen . split ( " " ) [ 0 ] ;
14- if ( ! fenBoard ) {
15- console . warn ( "Empty or invalid FEN:" , fen ) ;
16- return { } ;
17- }
14+ if ( ! fenBoard ) return { } ;
1815
1916 const rows = fenBoard . split ( "/" ) ;
20- if ( rows . length !== 8 ) {
21- console . warn ( "Invalid FEN rows count:" , rows . length , fen ) ;
22- return { } ;
23- }
24-
2517 const board : Record < string , string | null > = { } ;
2618
2719 for ( let r = 0 ; r < 8 ; r ++ ) {
2820 let fileIndex = 0 ;
2921 const currentRow = rows [ r ] ;
30-
31- if ( ! currentRow ) {
32- console . warn ( `Missing row ${ r } in FEN:` , fen ) ;
33- continue ;
34- }
22+ if ( ! currentRow ) continue ;
3523
3624 for ( const char of currentRow ) {
3725 if ( isNaN ( Number ( char ) ) ) {
38- const square = files [ fileIndex ] + ( 8 - r ) ;
26+ const square = defaultFiles [ fileIndex ] + ( 8 - r ) ;
3927 board [ square ] = char ;
4028 fileIndex ++ ;
4129 } else {
4230 const emptyCount = parseInt ( char , 10 ) ;
4331 for ( let i = 0 ; i < emptyCount ; i ++ ) {
44- const square = files [ fileIndex ] + ( 8 - r ) ;
32+ const square = defaultFiles [ fileIndex ] + ( 8 - r ) ;
4533 board [ square ] = null ;
4634 fileIndex ++ ;
4735 }
@@ -53,9 +41,13 @@ function fenToBoard(fen: string): Record<string, string | null> {
5341}
5442
5543const isLightSquare = ( file : string , rank : number ) =>
56- ( files . indexOf ( file ) + rank ) % 2 === 1 ;
44+ ( defaultFiles . indexOf ( file ) + rank ) % 2 === 1 ;
45+
46+ interface ChessBoardProps {
47+ boardOrientation ?: "white" | "black" ;
48+ }
5749
58- const ChessBoard = ( ) => {
50+ const ChessBoard = ( { boardOrientation = "white" } : ChessBoardProps ) => {
5951 const fen = useGameStore ( ( state ) => state . currentGame ?. fen || "" ) ;
6052 const selectedSquare = useGameStore ( ( state ) => state . selectedSquare ) ;
6153 const legalMoves = useGameStore ( ( state ) => state . legalMoves ) ;
@@ -66,6 +58,17 @@ const ChessBoard = () => {
6658
6759 const board = useMemo ( ( ) => fenToBoard ( fen ) , [ fen ] ) ;
6860
61+ const ranks = useMemo (
62+ ( ) =>
63+ boardOrientation === "white" ? defaultRanks : [ ...defaultRanks ] . reverse ( ) ,
64+ [ boardOrientation ]
65+ ) ;
66+ const files = useMemo (
67+ ( ) =>
68+ boardOrientation === "white" ? defaultFiles : [ ...defaultFiles ] . reverse ( ) ,
69+ [ boardOrientation ]
70+ ) ;
71+
6972 const onSquareClick = useCallback (
7073 ( square : string ) => {
7174 if ( ! currentGame ) return ;
@@ -119,15 +122,15 @@ const ChessBoard = () => {
119122 }
120123
121124 return (
122- < div className = "flex items-center justify-center p-6 " >
125+ < div className = "flex items-center justify-center w-full h-full " >
123126 < motion . div
124127 initial = { { opacity : 0 , scale : 0.95 } }
125128 animate = { { opacity : 1 , scale : 1 } }
126129 transition = { { duration : 0.5 , ease : "easeOut" } }
127- className = "relative"
130+ className = "relative w-full h-full max-w-[500px] max-h-[500px] aspect-square "
128131 >
129132 < div
130- className = "grid grid-cols-8 gap-0 w-96 h-96 border border-white/10 rounded-xl overflow-hidden shadow-2xl bg-card select-none"
133+ className = "grid grid-cols-8 grid-rows-8 w-full h-full border border-white/10 rounded-xl overflow-hidden shadow-2xl bg-card select-none"
131134 role = "grid"
132135 aria-label = "Chessboard"
133136 >
@@ -143,7 +146,7 @@ const ChessBoard = () => {
143146 < motion . div
144147 key = { square }
145148 className = { cn (
146- "w-12 h-12 flex items-center justify-center cursor-pointer relative transition-all duration-300" ,
149+ "w-full h-full flex items-center justify-center cursor-pointer relative transition-all duration-300" ,
147150 isLight
148151 ? "bg-amber-50 hover:bg-amber-100"
149152 : "bg-amber-700 hover:bg-amber-600" ,
@@ -166,8 +169,8 @@ const ChessBoard = () => {
166169 } }
167170 whileHover = { { scale : 1.05 , transition : { duration : 0.2 } } }
168171 whileTap = { { scale : 0.95 , transition : { duration : 0.1 } } }
169- initial = { { opacity : 0 , y : 20 } }
170- animate = { { opacity : 1 , y : 0 } }
172+ initial = { { opacity : 0 } }
173+ animate = { { opacity : 1 } }
171174 transition = { {
172175 delay : ( rankIndex * 8 + fileIndex ) * 0.01 ,
173176 duration : 0.3 ,
@@ -186,9 +189,9 @@ const ChessBoard = () => {
186189 damping : 25 ,
187190 duration : 0.4 ,
188191 } }
189- className = "relative z-10"
192+ className = "relative z-10 w-[75%] h-[75%] "
190193 >
191- < PieceIcon notation = { piece } size = { 32 } />
194+ < PieceIcon notation = { piece } />
192195 </ motion . div >
193196 ) }
194197 </ AnimatePresence >
@@ -204,7 +207,7 @@ const ChessBoard = () => {
204207 stiffness : 400 ,
205208 damping : 20 ,
206209 } }
207- className = "w-3 h-3 bg-primary rounded-full absolute"
210+ className = "w-[30%] h-[30%] bg-primary rounded-full absolute"
208211 />
209212 ) }
210213 </ AnimatePresence >
@@ -230,26 +233,30 @@ const ChessBoard = () => {
230233 ) }
231234 </ div >
232235
233- < div className = "absolute -bottom-6 left-0 right-0 flex justify-between px-3" >
234- { files . map ( ( file ) => (
235- < span
236- key = { file }
237- className = "text-xs text-muted-foreground font-medium w-12 text-center"
238- >
239- { file }
240- </ span >
241- ) ) }
242- </ div >
243- < div className = "absolute -left-6 top-0 bottom-0 flex flex-col justify-between py-3" >
244- { ranks . map ( ( rank ) => (
245- < span
246- key = { rank }
247- className = "text-xs text-muted-foreground font-medium h-12 flex items-center"
248- >
249- { rank }
250- </ span >
251- ) ) }
252- </ div >
236+ { files . map ( ( file , index ) => (
237+ < span
238+ key = { file }
239+ className = "text-xs text-muted-foreground font-medium absolute -bottom-5"
240+ style = { {
241+ left : `${ ( index + 0.5 ) * 12.5 } %` ,
242+ transform : "translateX(-50%)" ,
243+ } }
244+ >
245+ { file }
246+ </ span >
247+ ) ) }
248+ { ranks . map ( ( rank , index ) => (
249+ < span
250+ key = { rank }
251+ className = "text-xs text-muted-foreground font-medium absolute -left-5"
252+ style = { {
253+ top : `${ ( index + 0.5 ) * 12.5 } %` ,
254+ transform : "translateY(-50%)" ,
255+ } }
256+ >
257+ { rank }
258+ </ span >
259+ ) ) }
253260 </ motion . div >
254261 </ div >
255262 ) ;
0 commit comments