"use client"; import { Game } from "@chessu/types"; import { Chessboard } from "react-chessboard"; import { useEffect, useReducer, useState, useRef } from "react"; import { IconChevronLeft, IconChevronRight, IconCopy, IconPlayerSkipBack, IconPlayerSkipForward } from "@tabler/icons-react"; import type { Square } from "chess.js"; import { Chess } from "chess.js"; import type { CustomSquares } from "@/types"; import { IconRotateClockwise2 } from "@tabler/icons-react"; export default function ArchivedGame({ game }: { game: Game }) { const [boardWidth, setBoardWidth] = useState(480); const moveListRef = useRef(null); const [navFen, setNavFen] = useState(null); const [navIndex, setNavIndex] = useState(null); const [flipBoard, setFlipBoard] = useState(false); const [copiedLink, setCopiedLink] = useState(false); const [showPgn, setShowPgn] = useState(true); const actualGame = new Chess(); actualGame.loadPgn(game.pgn as string); const [customSquares, updateCustomSquares] = useReducer( (squares: CustomSquares, action: Partial) => { return { ...squares, ...action }; }, { options: {}, lastMove: {}, rightClicked: {}, check: {} } ); function handleResize() { if (window.innerWidth >= 1920) { setBoardWidth(580); } else if (window.innerWidth >= 1536) { setBoardWidth(540); } else if (window.innerWidth >= 768) { setBoardWidth(480); } else { setBoardWidth(350); } } // auto scroll for moves useEffect(() => { const activeMoveEl = document.getElementById("activeNavMove"); const moveList = moveListRef.current; if (!activeMoveEl || !moveList) return; moveList.scrollTop = activeMoveEl.offsetTop; }); useEffect(() => { handleResize(); window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); function copyLink() { const text = `https://ches.su/archive/${game.id}`; if ("clipboard" in navigator) { navigator.clipboard.writeText(text); } else { document.execCommand("copy", true, text); } setCopiedLink(true); setTimeout(() => { setCopiedLink(false); }, 5000); } function onSquareRightClick(square: Square) { const colour = "rgba(0, 0, 255, 0.4)"; updateCustomSquares({ rightClicked: { ...customSquares.rightClicked, [square]: customSquares.rightClicked[square] && customSquares.rightClicked[square]?.backgroundColor === colour ? undefined : { backgroundColor: colour } } }); } function getMoveListHtml() { const history = actualGame.history({ verbose: true }); const movePairs = history .slice(history.length / 2) .map((_, i) => history.slice((i *= 2), i + 2)); return movePairs.map((moves, i) => { return ( {i + 1}. navigateMove(history.indexOf(moves[0]))} > {moves[0].san} {moves[1] && ( navigateMove(history.indexOf(moves[1]))} > {moves[1].san} )} ); }); } function navigateMove(index: number | null | "prev") { const history = actualGame.history({ verbose: true }); if (index === null || (index !== "prev" && index >= history.length - 1) || !history.length) { // last move setNavIndex(null); setNavFen(null); return; } if (index === "prev") { index = history.length - 2; } else if (index < 0) { index = 0; } setNavIndex(index); setNavFen(history[index].after); } function getNavMoveSquares() { const history = actualGame.history({ verbose: true }); if (!history.length) return; let index = navIndex ?? history.length - 1; return { [history[index].from]: { background: "rgba(255, 255, 0, 0.4)" }, [history[index].to]: { background: "rgba(255, 255, 0, 0.4)" } }; } function getPlayerHtml(side: "top" | "bottom") { const blackHtml = (
{game.black?.name} black
); const whiteHtml = (
{game.white?.name} white
); if (flipBoard) { return side === "top" ? whiteHtml : blackHtml; } else { return side === "top" ? blackHtml : whiteHtml; } } return (
false} onSquareClick={() => updateCustomSquares({ rightClicked: {} })} onSquareRightClick={onSquareRightClick} customSquareStyles={{ ...getNavMoveSquares(), ...customSquares.rightClicked }} />
{getPlayerHtml("top")}
{getPlayerHtml("bottom")}
Archived link:
copied to clipboard
{getMoveListHtml()}
{game.endReason === "abandoned" ? game.winner === "draw" ? "The game ended in a draw due to abandonment." : `The game was won by ${game.winner} due to abandonment.` : game.winner === "draw" ? "The game ended in a draw." : `The game was won by checkmate (${game.winner}).`}