feat : add board style options UI

This commit is contained in:
GuillaumeSD
2025-05-10 19:52:12 +02:00
parent 10935c72c5
commit 82d216dfb0
26 changed files with 153 additions and 56 deletions

View File

@@ -0,0 +1,56 @@
import { Piece } from "react-chessboard/dist/chessboard/types";
export const PIECE_CODES = [
"wP",
"wB",
"wN",
"wR",
"wQ",
"wK",
"bP",
"bB",
"bN",
"bR",
"bQ",
"bK",
] as const satisfies Piece[];
export const PIECE_SETS = [
"alpha",
"anarcandy",
"caliente",
"california",
"cardinal",
"cburnett",
"celtic",
"chess7",
"chessnut",
"companion",
"cooke",
"dubrovny",
"fantasy",
"firi",
"fresca",
"gioco",
"governor",
"horsey",
"icpieces",
"kiwen-suwi",
"kosal",
"leipzig",
"letter",
"maestro",
"merida",
"monarchy",
"mpchess",
"pirouetti",
"pixel",
"reillycraig",
"rhosgfx",
"riohacha",
"shapes",
"spatial",
"staunty",
"tatiana",
"xkcd",
] as const satisfies string[];

View File

@@ -5,7 +5,6 @@ import {
Arrow,
CustomPieces,
CustomSquareRenderer,
Piece,
PromotionPieceOption,
Square,
} from "react-chessboard/dist/chessboard/types";
@@ -22,6 +21,7 @@ import PlayerHeader from "./playerHeader";
import Image from "next/image";
import { boardHueAtom, pieceSetAtom } from "./states";
import tinycolor from "tinycolor2";
import { PIECE_CODES } from "./constants";
export interface Props {
id: string;
@@ -233,7 +233,7 @@ export default function Board({
const customPieces = useMemo(
() =>
pieceCodes.reduce<CustomPieces>((acc, piece) => {
PIECE_CODES.reduce<CustomPieces>((acc, piece) => {
acc[piece] = ({ squareWidth }) => (
<Image
src={`/piece/${pieceSet}/${piece}.svg`}
@@ -325,18 +325,3 @@ export default function Board({
</Grid>
);
}
const pieceCodes = [
"wP",
"wB",
"wN",
"wR",
"wQ",
"wK",
"bP",
"bB",
"bN",
"bR",
"bQ",
"bK",
] as const satisfies Piece[];

View File

@@ -1,4 +1,8 @@
import { atomWithStorage } from "jotai/utils";
import { PIECE_SETS } from "./constants";
export const pieceSetAtom = atomWithStorage("pieceSet", "cburnett");
export const pieceSetAtom = atomWithStorage<(typeof PIECE_SETS)[number]>(
"pieceSet",
"maestro"
);
export const boardHueAtom = atomWithStorage("boardHue", 0);

View File

@@ -1,4 +1,9 @@
import { Grid2 as Grid, Slider as MuiSlider, Typography } from "@mui/material";
import {
Grid2 as Grid,
Slider as MuiSlider,
styled,
Typography,
} from "@mui/material";
export interface Props {
value: number;
@@ -28,11 +33,16 @@ export default function Slider({
alignItems="center"
size={size ?? 11}
>
<Typography id={`input-${label}`} textAlign="left" width="100%">
<Typography
id={`input-${label}`}
textAlign="left"
width="100%"
variant="body2"
>
{step === 1 && marksFilter ? label : `${label}: ${value}`}
</Typography>
<MuiSlider
<CustomSlider
min={min}
max={max}
marks={
@@ -52,3 +62,15 @@ export default function Slider({
</Grid>
);
}
const CustomSlider = styled(MuiSlider)(() => ({
".MuiSlider-markLabel": {
fontSize: "0.8rem",
lineHeight: "0.8rem",
},
".MuiSlider-thumb": {
width: "18px",
height: "18px",
},
marginBottom: "1rem",
}));

View File

@@ -24,6 +24,9 @@ import { useAtomLocalStorage } from "@/hooks/useAtomLocalStorage";
import { useEffect } from "react";
import { isEngineSupported } from "@/lib/engine/shared";
import { Stockfish16_1 } from "@/lib/engine/stockfish16_1";
import { useAtom } from "jotai";
import { boardHueAtom, pieceSetAtom } from "@/components/board/states";
import { PIECE_SETS } from "@/components/board/constants";
interface Props {
open: boolean;
@@ -43,6 +46,8 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
"engine-name",
engineNameAtom
);
const [boardHue, setBoardHue] = useAtom(boardHueAtom);
const [pieceSet, setPieceSet] = useAtom(pieceSetAtom);
useEffect(() => {
if (!isEngineSupported(engineName)) {
@@ -56,25 +61,33 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
return (
<Dialog open={open} onClose={onClose} maxWidth="md" fullWidth>
<DialogTitle marginY={1} variant="h5">
Set engine parameters
</DialogTitle>
<DialogTitle variant="h5">Settings</DialogTitle>
<DialogContent sx={{ paddingBottom: 0 }}>
<Typography>
Stockfish 17 Lite is the default engine if your device support its
requirements. It offers the best balance between speed and strength.
Stockfish 17 is the strongest engine available, note that it requires
a one time download of 75MB.
</Typography>
<Grid
marginTop={4}
container
justifyContent="center"
alignItems="center"
rowGap={3}
spacing={3}
size={12}
>
<Grid container justifyContent="center" size={12}>
<Grid
container
justifyContent="center"
size={{ xs: 12, sm: 7, md: 8 }}
>
<Typography>
Stockfish 17 Lite is the default engine if your device support its
requirements. It offers the best balance between speed and
strength. Stockfish 17 is the strongest engine available, note
that it requires a one time download of 75MB.
</Typography>
</Grid>
<Grid
container
justifyContent="center"
size={{ xs: 12, sm: 5, md: 4 }}
>
<FormControl variant="outlined">
<InputLabel id="dialog-select-label">Engine</InputLabel>
<Select
@@ -119,9 +132,48 @@ export default function EngineSettingsDialog({ open, onClose }: Props) {
/>
<ArrowOptions />
<Grid
container
justifyContent="center"
size={{ xs: 12, sm: 8, md: 9 }}
>
<Slider
label="Board hue"
value={boardHue}
setValue={setBoardHue}
min={0}
max={360}
/>
</Grid>
<Grid
container
justifyContent="center"
size={{ xs: 12, sm: 4, md: 3 }}
>
<FormControl variant="outlined">
<InputLabel id="dialog-select-label">Piece set</InputLabel>
<Select
labelId="dialog-select-label"
id="dialog-select"
displayEmpty
input={<OutlinedInput label="Piece set" />}
value={pieceSet}
onChange={(e) => setPieceSet(e.target.value)}
sx={{ width: 200, maxWidth: "100%" }}
>
{PIECE_SETS.map((name) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</Grid>
</DialogContent>
<DialogActions sx={{ m: 2 }}>
<DialogActions sx={{ m: 1 }}>
<Button variant="contained" onClick={onClose}>
Done
</Button>