@@ -5,9 +5,22 @@ import { defaults } from 'chessground/state'
55import type { Key } from 'chessground/types'
66import Chessground from '@react-chess/chessground'
77import { BaseGame , GameNode , Color } from 'src/types'
8+ import { MoveClassificationIcon } from 'src/components/Common/MoveIcons'
89import type { DrawBrushes , DrawShape } from 'chessground/draw'
910import { useCallback , useMemo , Dispatch , SetStateAction } from 'react'
1011
12+ interface MoveClassification {
13+ blunder : boolean
14+ inaccuracy : boolean
15+ excellent : boolean
16+ bestMove : boolean
17+ }
18+
19+ interface DestinationBadge {
20+ square : string
21+ classification : MoveClassification
22+ }
23+
1124interface Props {
1225 game ?: BaseGame
1326 currentNode : GameNode
@@ -20,6 +33,25 @@ interface Props {
2033 brushes ?: DrawBrushes
2134 goToNode ?: ( node : GameNode ) => void
2235 gameTree ?: any
36+ destinationBadges ?: DestinationBadge [ ]
37+ }
38+
39+ const getBoardSquarePosition = ( square : string , orientation : Color ) => {
40+ if ( ! / ^ [ a - h ] [ 1 - 8 ] $ / . test ( square ) ) {
41+ return null
42+ }
43+
44+ const file = square . charCodeAt ( 0 ) - 'a' . charCodeAt ( 0 )
45+ const rank = parseInt ( square [ 1 ] , 10 )
46+
47+ if ( Number . isNaN ( rank ) ) {
48+ return null
49+ }
50+
51+ return {
52+ left : orientation === 'white' ? file : 7 - file ,
53+ top : orientation === 'white' ? 8 - rank : rank - 1 ,
54+ }
2355}
2456
2557export const GameBoard : React . FC < Props > = ( {
@@ -34,8 +66,10 @@ export const GameBoard: React.FC<Props> = ({
3466 onPlayerMakeMove,
3567 setCurrentSquare,
3668 onSelectSquare,
69+ destinationBadges = [ ] ,
3770} : Props ) => {
3871 const { playMoveSound } = useSound ( )
72+
3973 const after = useCallback (
4074 ( from : string , to : string ) => {
4175 if ( onPlayerMakeMove ) onPlayerMakeMove ( [ from , to ] )
@@ -113,31 +147,65 @@ export const GameBoard: React.FC<Props> = ({
113147 } , [ currentNode , game , orientation ] )
114148
115149 return (
116- < Chessground
117- contained
118- config = { {
119- movable : {
120- free : false ,
121- dests : availableMoves as any ,
150+ < div className = "relative h-full w-full" >
151+ < Chessground
152+ contained
153+ config = { {
154+ movable : {
155+ free : false ,
156+ dests : availableMoves as any ,
157+ events : {
158+ after,
159+ } ,
160+ } ,
122161 events : {
123- after,
162+ select : ( key ) => {
163+ onSelectSquare && onSelectSquare ( key )
164+ setCurrentSquare && setCurrentSquare ( key )
165+ } ,
124166 } ,
125- } ,
126- events : {
127- select : ( key ) => {
128- onSelectSquare && onSelectSquare ( key )
129- setCurrentSquare && setCurrentSquare ( key )
167+ drawable : {
168+ autoShapes : shapes || [ ] ,
169+ brushes : { ...defaults ( ) . drawable . brushes , ...brushes } ,
130170 } ,
131- } ,
132- drawable : {
133- autoShapes : shapes || [ ] ,
134- brushes : { ...defaults ( ) . drawable . brushes , ...brushes } ,
135- } ,
136- fen : boardConfig . fen ,
137- lastMove : boardConfig . lastMove as Key [ ] ,
138- check : boardConfig . check ,
139- orientation : boardConfig . orientation ,
140- } }
141- />
171+ fen : boardConfig . fen ,
172+ lastMove : boardConfig . lastMove as Key [ ] ,
173+ check : boardConfig . check ,
174+ orientation : boardConfig . orientation ,
175+ } }
176+ />
177+ { destinationBadges . length > 0 ? (
178+ < div className = "pointer-events-none absolute inset-0 z-[40]" >
179+ { destinationBadges . map ( ( badge , index ) => {
180+ const squarePosition = getBoardSquarePosition (
181+ badge . square ,
182+ orientation ,
183+ )
184+ if ( ! squarePosition ) {
185+ return null
186+ }
187+
188+ return (
189+ < div
190+ key = { `${ badge . square } -${ index } ` }
191+ className = "absolute h-[12.5%] w-[12.5%] overflow-hidden"
192+ style = { {
193+ left : `${ squarePosition . left * 12.5 } %` ,
194+ top : `${ squarePosition . top * 12.5 } %` ,
195+ } }
196+ >
197+ < div className = "absolute right-0 top-0" >
198+ < MoveClassificationIcon
199+ classification = { badge . classification }
200+ size = "small"
201+ className = "!ml-0 !h-3.5 !w-3.5 !text-[9px] pointer-events-none"
202+ />
203+ </ div >
204+ </ div >
205+ )
206+ } ) }
207+ </ div >
208+ ) : null }
209+ </ div >
142210 )
143211}
0 commit comments