From 5de96cdc6ae7009ee04c24aa8a191f9d2db9f1a1 Mon Sep 17 00:00:00 2001 From: Francisco Salgueiro <92053465+franciscoBSalgueiro@users.noreply.github.com> Date: Fri, 10 Nov 2023 20:02:33 +0000 Subject: [PATCH] Add move tags in the chessboard (#79) * add annotation tags in the chessboard * use avatar instead of badge for hint * change last move color according to annotation * make badge color darker --- src/components/boards/BoardPlay.tsx | 129 +++++++++++++++++------ src/components/boards/PromotionModal.tsx | 19 +--- src/utils/chess.ts | 23 ++++ 3 files changed, 122 insertions(+), 49 deletions(-) diff --git a/src/components/boards/BoardPlay.tsx b/src/components/boards/BoardPlay.tsx index 4e4afdba..9633f5ab 100644 --- a/src/components/boards/BoardPlay.tsx +++ b/src/components/boards/BoardPlay.tsx @@ -1,7 +1,41 @@ +import { + autoPromoteAtom, + autoSaveAtom, + currentInvisibleAtom, + currentPracticingAtom, + currentTabAtom, + deckAtomFamily, + forcedEnPassantAtom, + moveInputAtom, + showArrowsAtom, + showCoordinatesAtom, + showDestsAtom, +} from "@/atoms/atoms"; +import { Chessground } from "@/chessground/Chessground"; +import { chessboard } from "@/styles/Chessboard.css"; +import { + ANNOTATION_INFO, + Annotation, + PiecesCount, + handleMove, + moveToCoordinates, + moveToKey, + parseKeyboardMove, + parseUci, + toDests, + useMaterialDiff, +} from "@/utils/chess"; +import { Outcome } from "@/utils/db"; +import { formatMove } from "@/utils/format"; +import { invoke } from "@/utils/invoke"; +import { getBoardSize } from "@/utils/misc"; +import { GameHeaders, TreeNode } from "@/utils/treeReducer"; import { ActionIcon, Alert, + Avatar, Box, + Global, Group, Input, Stack, @@ -20,44 +54,15 @@ import { IconPlus, IconSwitchVertical, } from "@tabler/icons-react"; -import { Chess, PieceSymbol, Square } from "chess.js"; +import { Chess, Move, PieceSymbol, Square } from "chess.js"; import { DrawShape } from "chessground/draw"; import { Color } from "chessground/types"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { memo, useContext, useMemo, useState } from "react"; -import { - handleMove, - moveToKey, - parseKeyboardMove, - parseUci, - PiecesCount, - toDests, - useMaterialDiff, -} from "@/utils/chess"; -import { Outcome } from "@/utils/db"; -import { formatMove } from "@/utils/format"; -import { invoke } from "@/utils/invoke"; -import { getBoardSize } from "@/utils/misc"; -import { GameHeaders, TreeNode } from "@/utils/treeReducer"; import { TreeDispatchContext } from "../common/TreeStateContext"; +import { updateCardPerformance } from "../files/opening"; import EvalBar from "./EvalBar"; -import { useAtom, useAtomValue, useSetAtom } from "jotai"; -import { - autoPromoteAtom, - autoSaveAtom, - currentInvisibleAtom, - currentPracticingAtom, - currentTabAtom, - deckAtomFamily, - forcedEnPassantAtom, - moveInputAtom, - showArrowsAtom, - showCoordinatesAtom, - showDestsAtom, -} from "@/atoms/atoms"; import PromotionModal from "./PromotionModal"; -import { updateCardPerformance } from "../files/opening"; -import { chessboard } from "@/styles/Chessboard.css"; -import { Chessground } from "@/chessground/Chessground"; interface ChessboardProps { dirty: boolean; @@ -284,6 +289,13 @@ function BoardPlay({ )} + {currentNode.annotation && currentNode.move && ( + + )} setPendingMove(null)} @@ -487,4 +499,57 @@ function ShowMaterial({ ); } +function AnnotationHint({ + move, + annotation, + orientation, +}: { + move: Move; + annotation: Annotation; + orientation: Color; +}) { + const { file, rank } = moveToCoordinates(move, orientation); + const { color } = ANNOTATION_INFO[annotation]; + + return ( + + + {annotation} + + ({ + "cg-board": { + "square.last-move": { + background: theme.fn.rgba( + theme.colors[color][ + theme.colorScheme === "dark" ? 8 : 6 + ], + 0.4 + ), + }, + }, + })} + /> + + ); +} + export default memo(BoardPlay); diff --git a/src/components/boards/PromotionModal.tsx b/src/components/boards/PromotionModal.tsx index c46204b8..4c65fae6 100644 --- a/src/components/boards/PromotionModal.tsx +++ b/src/components/boards/PromotionModal.tsx @@ -3,17 +3,7 @@ import { useClickOutside } from "@mantine/hooks"; import { BISHOP, KNIGHT, PieceSymbol, QUEEN, ROOK, Square } from "chess.js"; import { memo } from "react"; import Piece from "../common/Piece"; - -const fileToNumber: Record = { - a: 1, - b: 2, - c: 3, - d: 4, - e: 5, - f: 6, - g: 7, - h: 8, -}; +import { moveToCoordinates } from "@/utils/chess"; const PromotionModal = memo(function PromotionModal({ pendingMove, @@ -28,12 +18,7 @@ const PromotionModal = memo(function PromotionModal({ turn?: "white" | "black"; orientation: "white" | "black"; }) { - let file = fileToNumber[pendingMove?.to[0] ?? "a"]; - let rank = parseInt(pendingMove?.to[1] ?? "1"); - if (orientation === "black") { - file = 9 - file; - rank = 9 - rank; - } + const { file, rank } = moveToCoordinates(pendingMove, orientation) const ref = useClickOutside(() => cancelMove()); const promotionPieces: PieceSymbol[] = [QUEEN, KNIGHT, ROOK, BISHOP]; diff --git a/src/utils/chess.ts b/src/utils/chess.ts index b4ea74d9..0f9dc85c 100644 --- a/src/utils/chess.ts +++ b/src/utils/chess.ts @@ -266,6 +266,29 @@ export function moveToKey(move: Move | null) { return move ? ([move.from, move.to] as Key[]) : []; } + +const fileToNumber: Record = { + a: 1, + b: 2, + c: 3, + d: 4, + e: 5, + f: 6, + g: 7, + h: 8, +}; + + +export function moveToCoordinates(move: { from: string, to: string } | null, orientation: "white" | "black") { + let file = fileToNumber[move?.to[0] ?? "a"]; + let rank = parseInt(move?.to[1] ?? "1"); + if (orientation === "black") { + file = 9 - file; + rank = 9 - rank; + } + return { file, rank } +} + export function toDests( chess: Chess | null, forcedEP: boolean