refacto : board player header
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
"eslint:recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript",
|
||||
"plugin:@tanstack/eslint-plugin-query/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:deprecation/recommended",
|
||||
@@ -21,7 +22,7 @@
|
||||
"sourceType": "module"
|
||||
},
|
||||
"ignorePatterns": [".out/*"],
|
||||
"plugins": ["@typescript-eslint", "import", "prettier"],
|
||||
"plugins": ["@typescript-eslint", "import", "prettier", "@tanstack/query"],
|
||||
"rules": {
|
||||
"quotes": ["error", "double", { "avoidEscape": true }],
|
||||
"prettier/prettier": ["error", {"endOfLine": "auto"}],
|
||||
|
||||
45
package-lock.json
generated
45
package-lock.json
generated
@@ -17,6 +17,7 @@
|
||||
"@mui/material": "^6.3.0",
|
||||
"@mui/x-data-grid": "^7.23.5",
|
||||
"@sentry/nextjs": "^8.47.0",
|
||||
"@tanstack/react-query": "^5.75.5",
|
||||
"chess.js": "^1.2.0",
|
||||
"firebase": "^11.1.0",
|
||||
"idb": "^8.0.1",
|
||||
@@ -28,6 +29,7 @@
|
||||
"recharts": "^2.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tanstack/eslint-plugin-query": "^5.74.7",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/react": "18.2.11",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
@@ -3644,6 +3646,49 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/eslint-plugin-query": {
|
||||
"version": "5.74.7",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.74.7.tgz",
|
||||
"integrity": "sha512-EeHuaaYiCOD+XOGyB7LMNEx9OEByAa5lkgP+S3ZggjKJpmIO6iRWeoIYYDKo2F8uc3qXcVhTfC7pn7NddQiNtA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^8.18.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.75.5",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.75.5.tgz",
|
||||
"integrity": "sha512-kPDOxtoMn2Ycycb76Givx2fi+2pzo98F9ifHL/NFiahEDpDwSVW6o12PRuQ0lQnBOunhRG5etatAhQij91M3MQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.75.5",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.75.5.tgz",
|
||||
"integrity": "sha512-QrLCJe40BgBVlWdAdf2ZEVJ0cISOuEy/HKupId1aTKU6gPJZVhSvZpH+Si7csRflCJphzlQ77Yx6gUxGW9o0XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.75.5"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/connect": {
|
||||
"version": "3.4.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"@mui/material": "^6.3.0",
|
||||
"@mui/x-data-grid": "^7.23.5",
|
||||
"@sentry/nextjs": "^8.47.0",
|
||||
"@tanstack/react-query": "^5.75.5",
|
||||
"chess.js": "^1.2.0",
|
||||
"firebase": "^11.1.0",
|
||||
"idb": "^8.0.1",
|
||||
@@ -30,6 +31,7 @@
|
||||
"recharts": "^2.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tanstack/eslint-plugin-query": "^5.74.7",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/react": "18.2.11",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Grid2 as Grid, Typography } from "@mui/material";
|
||||
import { Grid2 as Grid } from "@mui/material";
|
||||
import { Chessboard } from "react-chessboard";
|
||||
import { PrimitiveAtom, atom, useAtomValue, useSetAtom } from "jotai";
|
||||
import {
|
||||
@@ -14,19 +14,17 @@ import { Chess } from "chess.js";
|
||||
import { getSquareRenderer } from "./squareRenderer";
|
||||
import { CurrentPosition } from "@/types/eval";
|
||||
import EvaluationBar from "./evaluationBar";
|
||||
import CapturedPieces from "./capturedPieces";
|
||||
import { moveClassificationColors } from "@/lib/chess";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import { Player } from "@/types/game";
|
||||
import PlayerHeader from "./playerHeader";
|
||||
|
||||
export interface Props {
|
||||
id: string;
|
||||
canPlay?: Color | boolean;
|
||||
gameAtom: PrimitiveAtom<Chess>;
|
||||
boardSize?: number;
|
||||
whitePlayer?: string;
|
||||
blackPlayer?: string;
|
||||
whiteAvatar?: string;
|
||||
blackAvatar?: string;
|
||||
whitePlayer: Player;
|
||||
blackPlayer: Player;
|
||||
boardOrientation?: Color;
|
||||
currentPositionAtom?: PrimitiveAtom<CurrentPosition>;
|
||||
showBestMoveArrow?: boolean;
|
||||
@@ -41,8 +39,6 @@ export default function Board({
|
||||
boardSize,
|
||||
whitePlayer,
|
||||
blackPlayer,
|
||||
whiteAvatar,
|
||||
blackAvatar,
|
||||
boardOrientation = Color.White,
|
||||
currentPositionAtom = atom({}),
|
||||
showBestMoveArrow = false,
|
||||
@@ -247,30 +243,11 @@ export default function Board({
|
||||
paddingLeft={showEvaluationBar ? 2 : 0}
|
||||
size="grow"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
columnGap={2}
|
||||
size={12}
|
||||
>
|
||||
{/* Player avatar, only render if URL is available */}
|
||||
{(boardOrientation === Color.White ? blackAvatar : whiteAvatar) && (
|
||||
<Avatar
|
||||
src={boardOrientation === Color.White ? blackAvatar : whiteAvatar}
|
||||
variant="circular"
|
||||
sx={{ width: 24, height: 24 }}
|
||||
/>
|
||||
) }
|
||||
<Typography>
|
||||
{boardOrientation === Color.White ? blackPlayer : whitePlayer}
|
||||
</Typography>
|
||||
|
||||
<CapturedPieces
|
||||
fen={gameFen}
|
||||
color={boardOrientation === Color.White ? Color.Black : Color.White}
|
||||
/>
|
||||
</Grid>
|
||||
<PlayerHeader
|
||||
color={boardOrientation === Color.White ? Color.Black : Color.White}
|
||||
fen={gameFen}
|
||||
player={boardOrientation === Color.White ? blackPlayer : whitePlayer}
|
||||
/>
|
||||
|
||||
<Grid
|
||||
container
|
||||
@@ -304,27 +281,11 @@ export default function Board({
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
columnGap={2}
|
||||
size={12}
|
||||
>
|
||||
{/* Player avatar, only render if URL is available */}
|
||||
{ (boardOrientation === Color.White ? whiteAvatar : blackAvatar) && (
|
||||
<Avatar
|
||||
src={boardOrientation === Color.White ? whiteAvatar : blackAvatar}
|
||||
variant="circular"
|
||||
sx={{ width: 24, height: 24 }}
|
||||
/>
|
||||
) }
|
||||
<Typography>
|
||||
{boardOrientation === Color.White ? whitePlayer : blackPlayer}
|
||||
</Typography>
|
||||
|
||||
<CapturedPieces fen={gameFen} color={boardOrientation} />
|
||||
</Grid>
|
||||
<PlayerHeader
|
||||
color={boardOrientation}
|
||||
fen={gameFen}
|
||||
player={boardOrientation === Color.White ? whitePlayer : blackPlayer}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
35
src/components/board/playerHeader.tsx
Normal file
35
src/components/board/playerHeader.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Color } from "@/types/enums";
|
||||
import { Player } from "@/types/game";
|
||||
import { Avatar, Grid2 as Grid, Typography } from "@mui/material";
|
||||
import CapturedPieces from "./capturedPieces";
|
||||
|
||||
export interface Props {
|
||||
player: Player;
|
||||
color: Color;
|
||||
fen: string;
|
||||
}
|
||||
|
||||
export default function PlayerHeader({ color, player, fen }: Props) {
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
columnGap={2}
|
||||
size={12}
|
||||
>
|
||||
{player.avatarUrl && (
|
||||
<Avatar
|
||||
src={player.avatarUrl}
|
||||
variant="circular"
|
||||
sx={{ width: 24, height: 24 }}
|
||||
/>
|
||||
)}
|
||||
<Typography>
|
||||
{player.rating ? `${player.name} (${player.rating})` : player.name}
|
||||
</Typography>
|
||||
|
||||
<CapturedPieces fen={fen} color={color} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import { Chess } from "chess.js";
|
||||
import { PrimitiveAtom, useAtomValue } from "jotai";
|
||||
import { useGameDatabase } from "./useGameDatabase";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getChessComUserAvatar } from "@/lib/chessCom";
|
||||
import { Player } from "@/types/game";
|
||||
|
||||
export const usePlayersNames = (gameAtom: PrimitiveAtom<Chess>) => {
|
||||
export const usePlayersData = (
|
||||
gameAtom: PrimitiveAtom<Chess>
|
||||
): { white: Player; black: Player } => {
|
||||
const game = useAtomValue(gameAtom);
|
||||
const { gameFromUrl } = useGameDatabase();
|
||||
const headers = game.getHeaders();
|
||||
@@ -16,57 +20,49 @@ export const usePlayersNames = (gameAtom: PrimitiveAtom<Chess>) => {
|
||||
const whiteName = gameFromUrl?.white?.name || headersWhiteName || "White";
|
||||
const blackName = gameFromUrl?.black?.name || headersBlackName || "Black";
|
||||
|
||||
const whiteElo = gameFromUrl?.white?.rating || headers.WhiteElo || undefined;
|
||||
const blackElo = gameFromUrl?.black?.rating || headers.BlackElo || undefined;
|
||||
const whiteElo =
|
||||
gameFromUrl?.white?.rating || Number(headers.WhiteElo) || undefined;
|
||||
const blackElo =
|
||||
gameFromUrl?.black?.rating || Number(headers.BlackElo) || undefined;
|
||||
|
||||
// Determine if this game came from Chess.com (via PGN header or URL)
|
||||
const siteHeader = gameFromUrl?.site || headers.Site || "";
|
||||
const siteHeader = gameFromUrl?.site || headers.Site || "unknown";
|
||||
const isChessCom = siteHeader.toLowerCase().includes("chess.com");
|
||||
|
||||
// Avatars fetched only for Chess.com games
|
||||
const [whiteAvatar, setWhiteAvatar] = useState<string | undefined>(undefined);
|
||||
const [blackAvatar, setBlackAvatar] = useState<string | undefined>(undefined);
|
||||
const whiteAvatarUrl = usePlayerAvatarUrl(
|
||||
whiteName,
|
||||
isChessCom && !!whiteName && whiteName !== "White"
|
||||
);
|
||||
|
||||
// Fetch white avatar
|
||||
useEffect(() => {
|
||||
if (isChessCom && whiteName && whiteName !== "White") {
|
||||
// Normalize and encode username
|
||||
const trimmedWhiteName = whiteName.trim().toLowerCase();
|
||||
const usernameParam = encodeURIComponent(trimmedWhiteName);
|
||||
fetch(`https://api.chess.com/pub/player/${usernameParam}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setWhiteAvatar(data.avatar || undefined))
|
||||
.catch(() => {
|
||||
setWhiteAvatar(undefined);
|
||||
});
|
||||
} else {
|
||||
setWhiteAvatar(undefined);
|
||||
}
|
||||
}, [isChessCom, whiteName]);
|
||||
|
||||
// Fetch black avatar
|
||||
useEffect(() => {
|
||||
if (isChessCom && blackName && blackName !== "Black") {
|
||||
// Normalize and encode username
|
||||
const trimmedBlackName = blackName.trim().toLowerCase();
|
||||
const usernameParamBlack = encodeURIComponent(trimmedBlackName);
|
||||
fetch(`https://api.chess.com/pub/player/${usernameParamBlack}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setBlackAvatar(data.avatar || undefined))
|
||||
.catch(() => {
|
||||
setBlackAvatar(undefined);
|
||||
});
|
||||
} else {
|
||||
setBlackAvatar(undefined);
|
||||
}
|
||||
}, [isChessCom, blackName]);
|
||||
const blackAvatarUrl = usePlayerAvatarUrl(
|
||||
blackName,
|
||||
isChessCom && !!blackName && blackName !== "Black"
|
||||
);
|
||||
|
||||
return {
|
||||
whiteName,
|
||||
blackName,
|
||||
whiteElo,
|
||||
blackElo,
|
||||
whiteAvatar,
|
||||
blackAvatar,
|
||||
white: {
|
||||
name: whiteName,
|
||||
rating: whiteElo,
|
||||
avatarUrl: whiteAvatarUrl ?? undefined,
|
||||
},
|
||||
black: {
|
||||
name: blackName,
|
||||
rating: blackElo,
|
||||
avatarUrl: blackAvatarUrl ?? undefined,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const usePlayerAvatarUrl = (
|
||||
playerName: string,
|
||||
enabled: boolean
|
||||
): string | null | undefined => {
|
||||
const { data: avatarUrl } = useQuery({
|
||||
queryKey: ["CCAvatar", playerName],
|
||||
enabled,
|
||||
queryFn: () => getChessComUserAvatar(playerName),
|
||||
staleTime: 1000 * 60 * 60, // 1 hour
|
||||
gcTime: 1000 * 60 * 60 * 24, // 1 day
|
||||
});
|
||||
|
||||
return avatarUrl;
|
||||
};
|
||||
|
||||
@@ -34,11 +34,11 @@ export const formatGameToDatabase = (game: Chess): Omit<Game, "id"> => {
|
||||
date: headers.Date,
|
||||
round: headers.Round ?? "?",
|
||||
white: {
|
||||
name: headers.White,
|
||||
name: headers.White || "White",
|
||||
rating: headers.WhiteElo ? Number(headers.WhiteElo) : undefined,
|
||||
},
|
||||
black: {
|
||||
name: headers.Black,
|
||||
name: headers.Black || "Black",
|
||||
rating: headers.BlackElo ? Number(headers.BlackElo) : undefined,
|
||||
},
|
||||
result: headers.Result,
|
||||
|
||||
@@ -39,3 +39,15 @@ export const getChessComUserRecentGames = async (
|
||||
|
||||
return gamesToReturn;
|
||||
};
|
||||
|
||||
export const getChessComUserAvatar = async (
|
||||
username: string
|
||||
): Promise<string | null> => {
|
||||
const usernameParam = encodeURIComponent(username.trim().toLowerCase());
|
||||
|
||||
const res = await fetch(`https://api.chess.com/pub/player/${usernameParam}`);
|
||||
const data = await res.json();
|
||||
const avatarUrl = data?.avatar;
|
||||
|
||||
return typeof avatarUrl === "string" ? avatarUrl : null;
|
||||
};
|
||||
|
||||
@@ -4,11 +4,16 @@ import "@fontsource/roboto/500.css";
|
||||
import "@fontsource/roboto/700.css";
|
||||
import { AppProps } from "next/app";
|
||||
import Layout from "@/sections/layout";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,14 +11,13 @@ import { useMemo } from "react";
|
||||
import { useScreenSize } from "@/hooks/useScreenSize";
|
||||
import { Color } from "@/types/enums";
|
||||
import Board from "@/components/board";
|
||||
import { usePlayersNames } from "@/hooks/usePlayerNames";
|
||||
import { usePlayersData } from "@/hooks/usePlayerNames";
|
||||
|
||||
export default function BoardContainer() {
|
||||
const screenSize = useScreenSize();
|
||||
const boardOrientation = useAtomValue(boardOrientationAtom);
|
||||
const showBestMoveArrow = useAtomValue(showBestMoveArrowAtom);
|
||||
const { whiteName, whiteElo, blackName, blackElo, whiteAvatar, blackAvatar } =
|
||||
usePlayersNames(gameAtom);
|
||||
const { white, black } = usePlayersData(gameAtom);
|
||||
|
||||
const boardSize = useMemo(() => {
|
||||
const width = screenSize.width;
|
||||
@@ -38,10 +37,8 @@ export default function BoardContainer() {
|
||||
boardSize={boardSize}
|
||||
canPlay={true}
|
||||
gameAtom={boardAtom}
|
||||
whitePlayer={whiteElo ? `${whiteName} (${whiteElo})` : whiteName}
|
||||
blackPlayer={blackElo ? `${blackName} (${blackElo})` : blackName}
|
||||
whiteAvatar={whiteAvatar}
|
||||
blackAvatar={blackAvatar}
|
||||
whitePlayer={white}
|
||||
blackPlayer={black}
|
||||
boardOrientation={boardOrientation ? Color.White : Color.Black}
|
||||
currentPositionAtom={currentPositionAtom}
|
||||
showBestMoveArrow={showBestMoveArrow}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { usePlayersNames } from "@/hooks/usePlayerNames";
|
||||
import { usePlayersData } from "@/hooks/usePlayerNames";
|
||||
import { Grid2 as Grid, Typography } from "@mui/material";
|
||||
import { gameAtom, gameEvalAtom } from "../../../states";
|
||||
import { MoveClassification } from "@/types/enums";
|
||||
@@ -6,7 +6,7 @@ import ClassificationRow from "./classificationRow";
|
||||
import { useAtomValue } from "jotai";
|
||||
|
||||
export default function MovesClassificationsRecap() {
|
||||
const { whiteName, blackName } = usePlayersNames(gameAtom);
|
||||
const { white, black } = usePlayersData(gameAtom);
|
||||
const gameEval = useAtomValue(gameEvalAtom);
|
||||
|
||||
if (!gameEval?.positions.length) return null;
|
||||
@@ -29,13 +29,13 @@ export default function MovesClassificationsRecap() {
|
||||
size={12}
|
||||
>
|
||||
<Typography width="12rem" align="center" noWrap fontSize="0.9rem">
|
||||
{whiteName}
|
||||
{white.name}
|
||||
</Typography>
|
||||
|
||||
<Typography width="7rem" />
|
||||
|
||||
<Typography width="12rem" align="center" noWrap fontSize="0.9rem">
|
||||
{blackName}
|
||||
{black.name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
value={engine}
|
||||
disabled={!isEngineSupported(engine)}
|
||||
>
|
||||
{engineLabel[engine]}
|
||||
{engineLabel[engine].full}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
@@ -129,12 +129,34 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
const engineLabel: Record<EngineName, string> = {
|
||||
[EngineName.Stockfish17]: "Stockfish 17 (75MB)",
|
||||
[EngineName.Stockfish17Lite]: "Stockfish 17 Lite (6MB)",
|
||||
[EngineName.Stockfish16_1]: "Stockfish 16.1 (64MB)",
|
||||
[EngineName.Stockfish16_1Lite]: "Stockfish 16.1 Lite (6MB)",
|
||||
[EngineName.Stockfish16NNUE]: "Stockfish 16 (40MB)",
|
||||
[EngineName.Stockfish16]: "Stockfish 16 Lite (HCE)",
|
||||
[EngineName.Stockfish11]: "Stockfish 11",
|
||||
};
|
||||
export const engineLabel: Record<EngineName, { small: string; full: string }> =
|
||||
{
|
||||
[EngineName.Stockfish17]: {
|
||||
full: "Stockfish 17 (75MB)",
|
||||
small: "Stockfish 17",
|
||||
},
|
||||
[EngineName.Stockfish17Lite]: {
|
||||
full: "Stockfish 17 Lite (6MB)",
|
||||
small: "Stockfish 17 Lite",
|
||||
},
|
||||
[EngineName.Stockfish16_1]: {
|
||||
full: "Stockfish 16.1 (64MB)",
|
||||
small: "Stockfish 16.1",
|
||||
},
|
||||
[EngineName.Stockfish16_1Lite]: {
|
||||
full: "Stockfish 16.1 Lite (6MB)",
|
||||
small: "Stockfish 16.1 Lite",
|
||||
},
|
||||
[EngineName.Stockfish16NNUE]: {
|
||||
full: "Stockfish 16 (40MB)",
|
||||
small: "Stockfish 16",
|
||||
},
|
||||
[EngineName.Stockfish16]: {
|
||||
full: "Stockfish 16 Lite (HCE)",
|
||||
small: "Stockfish 16 Lite",
|
||||
},
|
||||
[EngineName.Stockfish11]: {
|
||||
full: "Stockfish 11 (HCE)",
|
||||
small: "Stockfish 11",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,17 +10,18 @@ import {
|
||||
import { useChessActions } from "@/hooks/useChessActions";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useScreenSize } from "@/hooks/useScreenSize";
|
||||
import { Color } from "@/types/enums";
|
||||
import { useEngine } from "@/hooks/useEngine";
|
||||
import { uciMoveParams } from "@/lib/chess";
|
||||
import Board from "@/components/board";
|
||||
import { useGameData } from "@/hooks/useGameData";
|
||||
import { usePlayersData } from "@/hooks/usePlayerNames";
|
||||
|
||||
export default function BoardContainer() {
|
||||
const screenSize = useScreenSize();
|
||||
const engineName = useAtomValue(enginePlayNameAtom);
|
||||
const engine = useEngine(engineName, 1);
|
||||
const game = useAtomValue(gameAtom);
|
||||
const { white, black } = usePlayersData(gameAtom);
|
||||
const playerColor = useAtomValue(playerColorAtom);
|
||||
const { makeMove: makeGameMove } = useChessActions(gameAtom);
|
||||
const engineSkillLevel = useAtomValue(engineSkillLevelAtom);
|
||||
@@ -72,16 +73,8 @@ export default function BoardContainer() {
|
||||
canPlay={isGameInProgress ? playerColor : false}
|
||||
gameAtom={gameAtom}
|
||||
boardSize={boardSize}
|
||||
whitePlayer={
|
||||
playerColor === Color.White
|
||||
? "You 🧠"
|
||||
: `Stockfish level ${engineSkillLevel} 🤖`
|
||||
}
|
||||
blackPlayer={
|
||||
playerColor === Color.Black
|
||||
? "You 🧠"
|
||||
: `Stockfish level ${engineSkillLevel} 🤖`
|
||||
}
|
||||
whitePlayer={white}
|
||||
blackPlayer={black}
|
||||
boardOrientation={playerColor}
|
||||
currentPositionAtom={gameDataAtom}
|
||||
/>
|
||||
|
||||
@@ -32,6 +32,7 @@ import { logAnalyticsEvent } from "@/lib/firebase";
|
||||
import { useEffect } from "react";
|
||||
import { isEngineSupported } from "@/lib/engine/shared";
|
||||
import { Stockfish16_1 } from "@/lib/engine/stockfish16_1";
|
||||
import { engineLabel } from "@/sections/engineSettings/engineSettingsDialog";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -55,9 +56,13 @@ export default function GameSettingsDialog({ open, onClose }: Props) {
|
||||
onClose();
|
||||
resetGame({
|
||||
whiteName:
|
||||
playerColor === Color.White ? "You" : `Stockfish level ${skillLevel}`,
|
||||
playerColor === Color.White
|
||||
? "You"
|
||||
: `${engineLabel[engineName].small} level ${skillLevel}`,
|
||||
blackName:
|
||||
playerColor === Color.Black ? "You" : `Stockfish level ${skillLevel}`,
|
||||
playerColor === Color.Black
|
||||
? "You"
|
||||
: `${engineLabel[engineName].small} level ${skillLevel}`,
|
||||
});
|
||||
playGameStartSound();
|
||||
setIsGameInProgress(true);
|
||||
@@ -117,7 +122,7 @@ export default function GameSettingsDialog({ open, onClose }: Props) {
|
||||
value={engine}
|
||||
disabled={!isEngineSupported(engine)}
|
||||
>
|
||||
{engineLabel[engine]}
|
||||
{engineLabel[engine].full}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
@@ -166,13 +171,3 @@ export default function GameSettingsDialog({ open, onClose }: Props) {
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
const engineLabel: Record<EngineName, string> = {
|
||||
[EngineName.Stockfish17]: "Stockfish 17 (75MB)",
|
||||
[EngineName.Stockfish17Lite]: "Stockfish 17 Lite (6MB)",
|
||||
[EngineName.Stockfish16_1]: "Stockfish 16.1 (64MB)",
|
||||
[EngineName.Stockfish16_1Lite]: "Stockfish 16.1 Lite (6MB)",
|
||||
[EngineName.Stockfish16NNUE]: "Stockfish 16 (40MB)",
|
||||
[EngineName.Stockfish16]: "Stockfish 16 Lite (HCE)",
|
||||
[EngineName.Stockfish11]: "Stockfish 11",
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface Game {
|
||||
}
|
||||
|
||||
export interface Player {
|
||||
name?: string;
|
||||
name: string;
|
||||
rating?: number;
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user