feat: Improve move history table UX

- Remove auto-scroll to prevent page jumping when moves are added
- Add evaluation change column (Eval Δ) showing centipawn change per move
- Color-code evaluation changes (green=good, red=bad) based on player color
- Use moveHistory state instead of chess.js history for richer data display
- Keep chess board in view as primary focus
This commit is contained in:
Stefan
2025-11-25 19:34:52 +01:00
parent 35df6e145f
commit d83387debc
+41 -23
View File
@@ -85,10 +85,8 @@ export default function ChessGame({ initialFen, initialPgn, initialPersonality,
} }
}; };
// Scroll to bottom of move history // Removed auto-scroll to prevent page jumping when moves are added
useEffect(() => { // Users can manually scroll to see move history if needed
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [moveHistory]);
// Captured Pieces State // Captured Pieces State
const [capturedWhitePieces, setCapturedWhitePieces] = useState<string[]>([]); const [capturedWhitePieces, setCapturedWhitePieces] = useState<string[]>([]);
@@ -544,32 +542,52 @@ export default function ChessGame({ initialFen, initialPgn, initialPersonality,
<th className="py-1 px-2 w-12">#</th> <th className="py-1 px-2 w-12">#</th>
<th className="py-1 px-2">White</th> <th className="py-1 px-2">White</th>
<th className="py-1 px-2">Black</th> <th className="py-1 px-2">Black</th>
<th className="py-1 px-2 text-center w-20">Eval Δ</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{(() => { {moveHistory.length === 0 ? (
const history = gameRef.current.history(); <tr>
const rows = []; <td colSpan={4} className="py-4 text-center text-gray-500 italic">
for (let i = 0; i < history.length; i += 2) { No moves yet.
rows.push( </td>
<tr key={i} className="border-b border-gray-100 dark:border-gray-800 last:border-0"> </tr>
<td className="py-1 px-2 text-gray-500 dark:text-gray-500">{Math.floor(i / 2) + 1}.</td> ) : (
<td className="py-1 px-2 font-medium text-gray-900 dark:text-gray-200">{history[i]}</td> moveHistory.map((item, idx) => {
<td className="py-1 px-2 font-medium text-gray-900 dark:text-gray-200">{history[i + 1] || ""}</td> // Calculate evaluation change for player's move
</tr> const evalBefore = item.evalBeforePlayerMove.score ?? 0;
); const evalAfter = item.evalAfterPlayerMove.score ?? 0;
} const evalChange = evalAfter - evalBefore;
if (rows.length === 0) {
// Determine color based on evaluation change
// Positive change = good for white, negative = good for black
let evalColor = 'text-gray-500';
if (Math.abs(evalChange) > 50) {
if (item.playerColor === 'white') {
evalColor = evalChange > 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400';
} else {
evalColor = evalChange < 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400';
}
}
const evalDisplay = evalChange > 0 ? `+${(evalChange / 100).toFixed(1)}` : (evalChange / 100).toFixed(1);
return ( return (
<tr> <tr key={idx} className="border-b border-gray-100 dark:border-gray-800 last:border-0">
<td colSpan={3} className="py-4 text-center text-gray-500 italic"> <td className="py-1 px-2 text-gray-500 dark:text-gray-500">{item.moveNumber}.</td>
No moves yet. <td className="py-1 px-2 font-medium text-gray-900 dark:text-gray-200">
{item.playerColor === 'white' ? item.playerMove : item.computerMove}
</td>
<td className="py-1 px-2 font-medium text-gray-900 dark:text-gray-200">
{item.playerColor === 'black' ? item.playerMove : item.computerMove}
</td>
<td className={`py-1 px-2 text-center font-mono text-xs ${evalColor}`}>
{evalDisplay}
</td> </td>
</tr> </tr>
); );
} })
return rows; )}
})()}
</tbody> </tbody>
</table> </table>
<div ref={messagesEndRef} /> <div ref={messagesEndRef} />