feat : add board style options UI
This commit is contained in:
56
src/components/board/constants.ts
Normal file
56
src/components/board/constants.ts
Normal 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[];
|
||||
@@ -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[];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
}));
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user