diff --git a/src/sections/analysis/panelBody/analysisTab/chess_merida_unicode.ttf b/src/components/prettyMoveSan/chess_merida_unicode.ttf
similarity index 100%
rename from src/sections/analysis/panelBody/analysisTab/chess_merida_unicode.ttf
rename to src/components/prettyMoveSan/chess_merida_unicode.ttf
diff --git a/src/components/prettyMoveSan/index.tsx b/src/components/prettyMoveSan/index.tsx
new file mode 100644
index 0000000..7c011d0
--- /dev/null
+++ b/src/components/prettyMoveSan/index.tsx
@@ -0,0 +1,71 @@
+import {
+ Box,
+ BoxProps,
+ Typography,
+ TypographyProps,
+ useTheme,
+} from "@mui/material";
+import localFont from "next/font/local";
+import { useMemo } from "react";
+
+const chessFont = localFont({
+ src: "./chess_merida_unicode.ttf",
+});
+
+interface Props {
+ san: string;
+ color: "w" | "b";
+ additionalText?: string;
+ typographyProps?: TypographyProps;
+ boxProps?: BoxProps;
+}
+
+export default function PrettyMoveSan({
+ san,
+ color,
+ additionalText,
+ typographyProps,
+ boxProps,
+}: Props) {
+ const theme = useTheme();
+ const isDarkMode = theme.palette.mode === "dark";
+
+ const { icon, text } = useMemo(() => {
+ const firstChar = san.charAt(0);
+
+ const isPiece = ["K", "Q", "R", "B", "N"].includes(firstChar);
+ if (!isPiece) return { text: san };
+
+ const pieceColor = isDarkMode ? color : color === "w" ? "b" : "w";
+ const icon = unicodeMap[firstChar][pieceColor];
+
+ return { icon, text: san.slice(1) };
+ }, [san, color, isDarkMode]);
+
+ return (
+
+ {icon && (
+
+ {icon}
+
+ )}
+
+
+ {text}
+ {additionalText}
+
+
+ );
+}
+
+const unicodeMap: Record> = {
+ K: { w: "♚", b: "♔" },
+ Q: { w: "♛", b: "♕" },
+ R: { w: "♜", b: "♖" },
+ B: { w: "♝", b: "♗" },
+ N: { w: "♞", b: "♘" },
+};
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index f728e12..a929c8f 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -86,7 +86,7 @@ export default function GameAnalysis() {
gridTemplateRows={
gameEval
? "repeat(2, auto) max-content fit-content(100%) fit-content(100%) auto"
- : "repeat(3, auto) fit-content(100%)"
+ : "repeat(2, auto) max-content fit-content(100%)"
}
size={{
xs: 12,
diff --git a/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx b/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx
index aa7e735..522131d 100644
--- a/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx
+++ b/src/sections/analysis/panelBody/analysisTab/lineEvaluation.tsx
@@ -1,21 +1,16 @@
import { LineEval } from "@/types/eval";
-import { Box, ListItem, Skeleton, Typography, useTheme } from "@mui/material";
+import { ListItem, Skeleton, Typography } from "@mui/material";
import { useAtomValue } from "jotai";
import { boardAtom } from "../../states";
import { getLineEvalLabel, moveLineUciToSan } from "@/lib/chess";
-import localFont from "next/font/local";
import { useChessActions } from "@/hooks/useChessActions";
-
-const myFont = localFont({
- src: "./chess_merida_unicode.ttf",
-});
+import PrettyMoveSan from "@/components/prettyMoveSan";
interface Props {
line: LineEval;
}
export default function LineEvaluation({ line }: Props) {
- const theme = useTheme();
const board = useAtomValue(boardAtom);
const { addMoves } = useChessActions(boardAtom);
const lineLabel = getLineEvalLabel(line);
@@ -27,23 +22,11 @@ export default function LineEvaluation({ line }: Props) {
const showSkeleton = line.depth < 6;
const uciToSan = moveLineUciToSan(board.fen());
- const initialTurn = board.turn();
- const isDarkMode = theme.palette.mode === "dark";
+ const turn = board.turn();
- const formatSan = (
- san: string,
- moveIdx: number
- ): { icon?: string; text: string } => {
- const firstChar = san.charAt(0);
-
- const isPiece = ["K", "Q", "R", "B", "N"].includes(firstChar);
- if (!isPiece) return { text: san };
-
- const turn = isDarkMode ? initialTurn : initialTurn === "w" ? "b" : "w";
+ const getColorFromMoveIdx = (moveIdx: number): "w" | "b" => {
const moveColor = moveIdx % 2 === 0 ? turn : turn === "w" ? "b" : "w";
- const icon = unicodeMap[firstChar][moveColor];
-
- return { icon, text: san.slice(1) };
+ return moveColor;
};
return (
@@ -85,38 +68,28 @@ export default function LineEvaluation({ line }: Props) {
) : (
line.pv.map((uci, i) => {
const san = uciToSan(uci);
- const { icon, text } = formatSan(san, i);
+ const moveColor = getColorFromMoveIdx(i);
return (
- {
- addMoves(line.pv.slice(0, i + 1));
- }}
- sx={{
- cursor: "pointer",
- ml: i ? 0.5 : 0,
- transition: "opacity 0.2s ease-in-out",
- "&:hover": {
- opacity: 0.5,
+ san={san}
+ color={moveColor}
+ additionalText={i < line.pv.length - 1 ? "," : ""}
+ boxProps={{
+ onClick: () => {
+ addMoves(line.pv.slice(0, i + 1));
+ },
+ sx: {
+ cursor: "pointer",
+ ml: i ? 0.5 : 0,
+ transition: "opacity 0.2s ease-in-out",
+ "&:hover": {
+ opacity: 0.5,
+ },
},
}}
- >
- {icon && (
-
- {icon}
-
- )}
-
-
- {text}
- {i < line.pv.length - 1 && ","}
-
-
+ />
);
})
)}
@@ -124,11 +97,3 @@ export default function LineEvaluation({ line }: Props) {
);
}
-
-const unicodeMap: Record> = {
- K: { w: "♚", b: "♔" },
- Q: { w: "♛", b: "♕" },
- R: { w: "♜", b: "♖" },
- B: { w: "♝", b: "♗" },
- N: { w: "♞", b: "♘" },
-};
diff --git a/src/sections/analysis/panelBody/analysisTab/moveInfo.tsx b/src/sections/analysis/panelBody/analysisTab/moveInfo.tsx
index 82af1ea..0887c0f 100644
--- a/src/sections/analysis/panelBody/analysisTab/moveInfo.tsx
+++ b/src/sections/analysis/panelBody/analysisTab/moveInfo.tsx
@@ -5,6 +5,7 @@ import { useMemo } from "react";
import { moveLineUciToSan } from "@/lib/chess";
import { MoveClassification } from "@/types/enums";
import Image from "next/image";
+import PrettyMoveSan from "@/components/prettyMoveSan";
export default function MoveInfo() {
const position = useAtomValue(currentPositionAtom);
@@ -56,18 +57,13 @@ export default function MoveInfo() {
}
const moveClassification = position.eval?.moveClassification;
- const moveLabel = moveClassification
- ? `${position.lastMove?.san} is ${moveClassificationLabels[moveClassification]}`
- : null;
- const bestMoveLabel =
- moveClassification === MoveClassification.Best ||
- moveClassification === MoveClassification.Opening ||
- moveClassification === MoveClassification.Forced ||
- moveClassification === MoveClassification.Splendid ||
- moveClassification === MoveClassification.Perfect
- ? null
- : `${bestMoveSan} was the best move`;
+ const showBestMoveLabel =
+ moveClassification !== MoveClassification.Best &&
+ moveClassification !== MoveClassification.Opening &&
+ moveClassification !== MoveClassification.Forced &&
+ moveClassification !== MoveClassification.Splendid &&
+ moveClassification !== MoveClassification.Perfect;
return (
- {moveLabel && (
+ {moveClassification && (
- {moveClassification && (
-
- )}
-
- {moveLabel}
-
+
+
+
)}
- {bestMoveLabel && (
+ {showBestMoveLabel && (
-
- {bestMoveLabel}
-
+
)}
diff --git a/src/sections/analysis/panelBody/classificationTab/movesPanel/index.tsx b/src/sections/analysis/panelBody/classificationTab/movesPanel/index.tsx
index d310602..7d8e48c 100644
--- a/src/sections/analysis/panelBody/classificationTab/movesPanel/index.tsx
+++ b/src/sections/analysis/panelBody/classificationTab/movesPanel/index.tsx
@@ -42,7 +42,8 @@ export default function MovesPanel() {
container
justifyContent="center"
alignItems="start"
- gap={0.6}
+ gap={0.7}
+ paddingY={1}
sx={{ scrollbarWidth: "thin", overflowY: "auto" }}
height="100%"
size={6}
diff --git a/src/sections/analysis/panelBody/classificationTab/movesPanel/moveItem.tsx b/src/sections/analysis/panelBody/classificationTab/movesPanel/moveItem.tsx
index 7ca2324..b954234 100644
--- a/src/sections/analysis/panelBody/classificationTab/movesPanel/moveItem.tsx
+++ b/src/sections/analysis/panelBody/classificationTab/movesPanel/moveItem.tsx
@@ -1,5 +1,5 @@
import { MoveClassification } from "@/types/enums";
-import { Grid2 as Grid, Typography } from "@mui/material";
+import { Grid2 as Grid } from "@mui/material";
import Image from "next/image";
import { useAtomValue } from "jotai";
import { boardAtom, currentPositionAtom, gameAtom } from "../../../states";
@@ -7,14 +7,21 @@ import { useChessActions } from "@/hooks/useChessActions";
import { useEffect } from "react";
import { isInViewport } from "@/lib/helpers";
import { CLASSIFICATION_COLORS } from "@/constants";
+import PrettyMoveSan from "@/components/prettyMoveSan";
interface Props {
san: string;
moveClassification?: MoveClassification;
moveIdx: number;
+ moveColor: "w" | "b";
}
-export default function MoveItem({ san, moveClassification, moveIdx }: Props) {
+export default function MoveItem({
+ san,
+ moveClassification,
+ moveIdx,
+ moveColor,
+}: Props) {
const game = useAtomValue(gameAtom);
const { goToMove } = useChessActions(boardAtom);
const position = useAtomValue(currentPositionAtom);
@@ -47,7 +54,7 @@ export default function MoveItem({ san, moveClassification, moveIdx }: Props) {
width="5rem"
wrap="nowrap"
onClick={handleClick}
- paddingY={0.6}
+ paddingY={0.5}
sx={(theme) => ({
cursor: isCurrentMove ? undefined : "pointer",
backgroundColor:
@@ -74,9 +81,8 @@ export default function MoveItem({ san, moveClassification, moveIdx }: Props) {
}}
/>
)}
-
- {san}
-
+
+
);
}
diff --git a/src/sections/analysis/panelBody/classificationTab/movesPanel/movesLine.tsx b/src/sections/analysis/panelBody/classificationTab/movesPanel/movesLine.tsx
index 51acb1d..875aebc 100644
--- a/src/sections/analysis/panelBody/classificationTab/movesPanel/movesLine.tsx
+++ b/src/sections/analysis/panelBody/classificationTab/movesPanel/movesLine.tsx
@@ -1,5 +1,5 @@
import { MoveClassification } from "@/types/enums";
-import { Grid2 as Grid, Typography } from "@mui/material";
+import { Box, Grid2 as Grid, Typography } from "@mui/material";
import MoveItem from "./moveItem";
interface Props {
@@ -20,9 +20,13 @@ export default function MovesLine({ moves, moveNb }: Props) {
{moveNb}.
-
+
-
+ {moves[1] ? (
+
+ ) : (
+
+ )}
);
}