Skip to content

Commit f02dc33

Browse files
feat: improve movemap to show all moves + improve movetooltip across components
1 parent 959f29d commit f02dc33

7 files changed

Lines changed: 439 additions & 146 deletions

File tree

src/components/Analysis/BlunderMeter.tsx

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
1-
import React, { useContext } from 'react'
1+
import React, { useContext, useState } from 'react'
22
import { motion } from 'framer-motion'
33

44
import { BlunderMeterResult, ColorSanMapping } from 'src/types'
55
import { WindowSizeContext } from 'src/contexts'
6+
import { MoveTooltip } from './MoveTooltip'
67

78
interface Props {
89
data: BlunderMeterResult
910
colorSanMapping: ColorSanMapping
1011
hover: (move?: string) => void
1112
makeMove: (move: string) => void
13+
moveEvaluation?: {
14+
maia?: { policy: { [key: string]: number } }
15+
stockfish?: {
16+
cp_vec: { [key: string]: number }
17+
winrate_vec?: { [key: string]: number }
18+
winrate_loss_vec?: { [key: string]: number }
19+
}
20+
} | null
1221
}
1322

1423
export const BlunderMeter: React.FC<Props> = ({
1524
data,
1625
hover,
1726
makeMove,
1827
colorSanMapping,
28+
moveEvaluation,
1929
}: Props) => {
2030
const { isMobile } = useContext(WindowSizeContext)
2131

@@ -25,13 +35,15 @@ export const BlunderMeter: React.FC<Props> = ({
2535
hover={hover}
2636
makeMove={makeMove}
2737
colorSanMapping={colorSanMapping}
38+
moveEvaluation={moveEvaluation}
2839
/>
2940
) : (
3041
<DesktopBlunderMeter
3142
data={data}
3243
hover={hover}
3344
makeMove={makeMove}
3445
colorSanMapping={colorSanMapping}
46+
moveEvaluation={moveEvaluation}
3547
/>
3648
)
3749
}
@@ -41,6 +53,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
4153
hover,
4254
makeMove,
4355
colorSanMapping,
56+
moveEvaluation,
4457
}: Props) => {
4558
return (
4659
<div className="flex h-64 max-h-full w-full flex-col gap-2 overflow-hidden rounded bg-background-1/60 p-3 md:h-full md:w-auto md:min-w-[40%] md:max-w-[40%]">
@@ -56,6 +69,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
5669
bgColor="bg-[#1a9850] rounded-t"
5770
probability={data.goodMoves.probability}
5871
colorSanMapping={colorSanMapping}
72+
moveEvaluation={moveEvaluation}
5973
/>
6074
<Meter
6175
hover={hover}
@@ -66,6 +80,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
6680
textColor="text-[#fee08b]"
6781
probability={data.okMoves.probability}
6882
colorSanMapping={colorSanMapping}
83+
moveEvaluation={moveEvaluation}
6984
/>
7085
<Meter
7186
hover={hover}
@@ -76,6 +91,7 @@ const DesktopBlunderMeter: React.FC<Props> = ({
7691
moves={data.blunderMoves.moves}
7792
probability={data.blunderMoves.probability}
7893
colorSanMapping={colorSanMapping}
94+
moveEvaluation={moveEvaluation}
7995
/>
8096
</div>
8197
</div>
@@ -88,6 +104,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
88104
hover,
89105
makeMove,
90106
colorSanMapping,
107+
moveEvaluation,
91108
}: Props) => {
92109
return (
93110
<div className="flex w-full flex-col gap-2 overflow-hidden rounded bg-background-1/60 p-3">
@@ -135,6 +152,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
135152
hover={hover}
136153
makeMove={makeMove}
137154
colorSanMapping={colorSanMapping}
155+
moveEvaluation={moveEvaluation}
138156
/>
139157
<MovesList
140158
title="Meh Moves"
@@ -143,6 +161,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
143161
hover={hover}
144162
makeMove={makeMove}
145163
colorSanMapping={colorSanMapping}
164+
moveEvaluation={moveEvaluation}
146165
/>
147166
<MovesList
148167
title="Blunders"
@@ -151,6 +170,7 @@ const MobileBlunderMeter: React.FC<Props> = ({
151170
hover={hover}
152171
makeMove={makeMove}
153172
colorSanMapping={colorSanMapping}
173+
moveEvaluation={moveEvaluation}
154174
/>
155175
</div>
156176
</div>
@@ -165,18 +185,45 @@ function MovesList({
165185
hover,
166186
makeMove,
167187
colorSanMapping,
188+
moveEvaluation,
168189
}: {
169190
title: string
170191
textColor: string
171192
moves: { move: string; probability: number }[]
172193
hover: (move?: string) => void
173194
makeMove: (move: string) => void
174195
colorSanMapping: ColorSanMapping
196+
moveEvaluation?: {
197+
maia?: { policy: { [key: string]: number } }
198+
stockfish?: {
199+
cp_vec: { [key: string]: number }
200+
winrate_vec?: { [key: string]: number }
201+
winrate_loss_vec?: { [key: string]: number }
202+
}
203+
}
175204
}) {
205+
const [tooltipData, setTooltipData] = useState<{
206+
move: string
207+
position: { x: number; y: number }
208+
} | null>(null)
209+
176210
const filteredMoves = () => {
177211
return moves.slice(0, 6).filter((move) => move.probability >= 8)
178212
}
179213

214+
const handleMouseEnter = (move: string, event: React.MouseEvent) => {
215+
hover(move)
216+
setTooltipData({
217+
move,
218+
position: { x: event.clientX, y: event.clientY },
219+
})
220+
}
221+
222+
const handleMouseLeave = () => {
223+
hover()
224+
setTooltipData(null)
225+
}
226+
180227
return (
181228
<div className="flex flex-col">
182229
<p className={`text-sm font-medium ${textColor}`}>{title}</p>
@@ -185,15 +232,32 @@ function MovesList({
185232
<button
186233
key={move.move}
187234
className="text-left hover:underline"
188-
onMouseLeave={() => hover()}
189-
onMouseEnter={() => hover(move.move)}
235+
onMouseLeave={handleMouseLeave}
236+
onMouseEnter={(e) => handleMouseEnter(move.move, e)}
190237
onClick={() => makeMove(move.move)}
191238
>
192239
{colorSanMapping[move.move]?.san || move.move} (
193240
{Math.round(move.probability)}%)
194241
</button>
195242
))}
196243
</div>
244+
245+
{/* Tooltip */}
246+
{tooltipData && moveEvaluation && (
247+
<MoveTooltip
248+
move={tooltipData.move}
249+
colorSanMapping={colorSanMapping}
250+
maiaProb={moveEvaluation.maia?.policy[tooltipData.move]}
251+
stockfishCp={moveEvaluation.stockfish?.cp_vec[tooltipData.move]}
252+
stockfishWinrate={
253+
moveEvaluation.stockfish?.winrate_vec?.[tooltipData.move]
254+
}
255+
stockfishLoss={
256+
moveEvaluation.stockfish?.winrate_loss_vec?.[tooltipData.move]
257+
}
258+
position={tooltipData.position}
259+
/>
260+
)}
197261
</div>
198262
)
199263
}
@@ -245,6 +309,7 @@ function Meter({
245309
textColor,
246310
probability,
247311
colorSanMapping,
312+
moveEvaluation,
248313
}: {
249314
title: string
250315
textColor: string
@@ -254,11 +319,37 @@ function Meter({
254319
makeMove: (move: string) => void
255320
colorSanMapping: ColorSanMapping
256321
moves: { move: string; probability: number }[]
322+
moveEvaluation?: {
323+
maia?: { policy: { [key: string]: number } }
324+
stockfish?: {
325+
cp_vec: { [key: string]: number }
326+
winrate_vec?: { [key: string]: number }
327+
winrate_loss_vec?: { [key: string]: number }
328+
}
329+
}
257330
}) {
331+
const [tooltipData, setTooltipData] = useState<{
332+
move: string
333+
position: { x: number; y: number }
334+
} | null>(null)
335+
258336
const filteredMoves = () => {
259337
return moves.slice(0, 6).filter((move) => move.probability >= 8)
260338
}
261339

340+
const handleMouseEnter = (move: string, event: React.MouseEvent) => {
341+
hover(move)
342+
setTooltipData({
343+
move,
344+
position: { x: event.clientX, y: event.clientY },
345+
})
346+
}
347+
348+
const handleMouseLeave = () => {
349+
hover()
350+
setTooltipData(null)
351+
}
352+
262353
return (
263354
<motion.div
264355
className="flex min-h-6 w-full flex-row items-start justify-start gap-2 overflow-hidden"
@@ -282,8 +373,8 @@ function Meter({
282373
<button
283374
key={move.move}
284375
className="text-left hover:underline"
285-
onMouseLeave={() => hover()}
286-
onMouseEnter={() => hover(move.move)}
376+
onMouseLeave={handleMouseLeave}
377+
onMouseEnter={(e) => handleMouseEnter(move.move, e)}
287378
onClick={() => makeMove(move.move)}
288379
>
289380
{colorSanMapping[move.move]?.san || move.move} (
@@ -292,6 +383,23 @@ function Meter({
292383
))}
293384
</div>
294385
</div>
386+
387+
{/* Tooltip */}
388+
{tooltipData && moveEvaluation && (
389+
<MoveTooltip
390+
move={tooltipData.move}
391+
colorSanMapping={colorSanMapping}
392+
maiaProb={moveEvaluation.maia?.policy[tooltipData.move]}
393+
stockfishCp={moveEvaluation.stockfish?.cp_vec[tooltipData.move]}
394+
stockfishWinrate={
395+
moveEvaluation.stockfish?.winrate_vec?.[tooltipData.move]
396+
}
397+
stockfishLoss={
398+
moveEvaluation.stockfish?.winrate_loss_vec?.[tooltipData.move]
399+
}
400+
position={tooltipData.position}
401+
/>
402+
)}
295403
</motion.div>
296404
)
297405
}

0 commit comments

Comments
 (0)