diff --git a/package-lock.json b/package-lock.json index 82d457f..3779791 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "h264-mp4-encoder": "^1.0.12", "hammerjs": "^2.0.8", "i": "^0.3.7", + "is-mobile": "^3.0.0", "npm": "^8.4.0", "webfontloader": "^1.6.28", "webm-writer": "^1.0.0" @@ -1078,6 +1079,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-mobile": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-3.0.0.tgz", + "integrity": "sha512-UruBjgykgDJ5zRpJ8Zgh9ZUe4jQaHD8klX9FlkOt0oPyu3FpwJpxHvKg4+lhJOWGxSrMKsRuPFk60xeltvyliQ==" + }, "node_modules/is-what": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.7.tgz", @@ -4471,6 +4477,11 @@ "has": "^1.0.3" } }, + "is-mobile": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-3.0.0.tgz", + "integrity": "sha512-UruBjgykgDJ5zRpJ8Zgh9ZUe4jQaHD8klX9FlkOt0oPyu3FpwJpxHvKg4+lhJOWGxSrMKsRuPFk60xeltvyliQ==" + }, "is-what": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.7.tgz", diff --git a/package.json b/package.json index 6d7913e..2aaae2c 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "h264-mp4-encoder": "^1.0.12", "hammerjs": "^2.0.8", "i": "^0.3.7", + "is-mobile": "^3.0.0", "npm": "^8.4.0", "webfontloader": "^1.6.28", "webm-writer": "^1.0.0" diff --git a/src/board/Board.ts b/src/board/Board.ts index 08f4b46..61ca26d 100644 --- a/src/board/Board.ts +++ b/src/board/Board.ts @@ -35,7 +35,6 @@ class Board { private style: Style = boards.standard; private header: { [key: string]: string | undefined } = {}; - private borderVisible: boolean = true; private lastPosition: Position | null = null; private background: HTMLCanvasElement | null = null; private currentScreen: "title" | "move" = "move"; @@ -100,7 +99,7 @@ class Board { this.tempCanvas.height = height; } - const tempBorderWidth = this.borderVisible ? this.size / 32 : 0; + const tempBorderWidth = this.cfg.showBorder ? this.size / 32 : 0; const tempInnerSize = this.size - tempBorderWidth * 2; this.squareSize = Math.floor(tempInnerSize / this.cfg.tiles); this.innerSize = this.squareSize * this.cfg.tiles; @@ -132,21 +131,21 @@ class Board { } hideBorder() { - this.borderVisible = false; + this.cfg.showBorder = false; this.setSize(this.size); this.refresh(); return this; } showBorder() { - this.borderVisible = true; + this.cfg.showBorder = true; this.setSize(this.size); this.refresh(); return this; } toggleBorder() { - this.borderVisible = !this.borderVisible; + this.cfg.showBorder = !this.cfg.showBorder; this.setSize(this.size); this.refresh(); return this; @@ -188,8 +187,8 @@ class Board { ctx, this.innerSize, this.innerSize, - this.borderVisible ? this.borderWidth : 0, - (this.borderVisible ? this.borderWidth : 0) + this.margin, + this.cfg.showBorder ? this.borderWidth : 0, + (this.cfg.showBorder ? this.borderWidth : 0) + this.margin, background ); @@ -208,7 +207,7 @@ class Board { } } - if (this.borderVisible && this.cfg.showCoords) { + if (this.cfg.showBorder && this.cfg.showCoords) { drawCoords( ctx, coords, @@ -217,7 +216,7 @@ class Board { this.cfg.flipped, this.borderWidth, this.size, - this.borderVisible, + this.cfg.showBorder, this.margin ); } @@ -254,7 +253,7 @@ class Board { ); } - if (!this.borderVisible && this.cfg.showCoords) { + if (!this.cfg.showBorder && this.cfg.showCoords) { drawCoords( this.tempCtx, this.style.coords, @@ -263,7 +262,7 @@ class Board { this.cfg.flipped, this.borderWidth, this.size, - this.borderVisible, + this.cfg.showBorder, this.margin ); } diff --git a/src/board/layers/drawExtraInfo.ts b/src/board/layers/drawExtraInfo.ts index 99de462..39be0c8 100644 --- a/src/board/layers/drawExtraInfo.ts +++ b/src/board/layers/drawExtraInfo.ts @@ -29,10 +29,10 @@ const drawExtraInfo = async ( ctx.fillStyle = style.coords.onBorder; - if (data.White) { + { const w = drawText( ctx, - data.White, + data.White ?? "White", "Ubuntu", fontSize, 700, @@ -56,13 +56,10 @@ const drawExtraInfo = async ( ); } - if (data.Black) { - const elo = - data.BlackElo && data.BlackElo !== "?" ? ` ${data.BlackElo}` : ""; - + { const w = drawText( ctx, - data.Black, + data.Black ?? "Black", "Ubuntu", fontSize, 700, @@ -71,6 +68,9 @@ const drawExtraInfo = async ( "left" ); + const elo = + data.BlackElo && data.BlackElo !== "?" ? ` ${data.BlackElo}` : ""; + drawText( ctx, elo, diff --git a/src/encoders/createImage.ts b/src/encoders/createImage.ts index 995b278..100d07d 100644 --- a/src/encoders/createImage.ts +++ b/src/encoders/createImage.ts @@ -1,17 +1,28 @@ -import { BoardConfig } from "../types"; +import { BoardConfig, Size } from "../types"; import Board from "../board/Board"; import Game from "../game/Game"; +import sizeToPX from "./sizeToPX"; const createImage = async ( fen: string, + pgn: string | null, + ply: number = 0, boardConfig: BoardConfig, - size: number + size: Size ) => { - const game = new Game().loadFEN(fen); - const board = new Board({ ...boardConfig, size }); + console.log({ fen, pgn, ply, size }); + const game = new Game(); - const position = game.getPosition(0); - await board.frame(position, {}); + if (pgn) { + game.loadPGN(pgn); + } else { + game.loadFEN(fen); + } + + const board = new Board({ ...boardConfig, size: sizeToPX[size] }); + + const position = game.getPosition(ply); + await board.frame(position, game.header); board.render(); return board.toImgUrl(); diff --git a/src/encoders/sizeToPX.ts b/src/encoders/sizeToPX.ts new file mode 100644 index 0000000..355f5a2 --- /dev/null +++ b/src/encoders/sizeToPX.ts @@ -0,0 +1,9 @@ +const sizeToPX = { + XS: 256, + S: 512, + M: 720, + L: 1024, + XL: 1440, +}; + +export default sizeToPX; diff --git a/src/game/Game.ts b/src/game/Game.ts index 6ac03b3..077a798 100644 --- a/src/game/Game.ts +++ b/src/game/Game.ts @@ -76,8 +76,8 @@ class Game { move: null, end: 0, fen, - check: false, - mate: false, + check: this.game.in_check(), + mate: this.game.in_checkmate(), turn: this.game.turn(), material: this.materialInfo(this.game.board()), placement: this.getPlacement(this.game.fen()), diff --git a/src/main.tsx b/src/main.tsx index 34eb750..4771efc 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -67,7 +67,12 @@ const main = async () => { const player = new Player(board, gameConfig); const game = new Game().loadPGN(pgn); - setState({ moves: game.getMoves() }); + setState({ + moves: game.getMoves(), + pgn, + ply: 0, + fen: game.getPosition(0).fen, + }); const handlers = { prev() { @@ -88,19 +93,24 @@ const main = async () => { }, toggleBorder() { board.toggleBorder(); + setState("board", "showBorder", !state.board.showBorder); }, showBorder() { board.showBorder(); + setState("board", "showBorder", true); }, hideBorder() { board.hideBorder(); + setState("board", "showBorder", false); }, toggleExtraInfo() { board.toggleExtraInfo(); + setState("board", "showExtraInfo", !state.board.showExtraInfo); }, flip() { board.flip(); + setState("board", "flipped", !state.board.flipped); }, togglePlay() { player.playing ? player.pause() : player.play(); @@ -111,9 +121,11 @@ const main = async () => { }, changeBoardStyle(style: BoardStyle) { board.setStyle(style); + setState("board", "boardStyle", style); }, changePiecesStyle(style: PiecesStyle) { board.setPiecesStyle(style); + setState("board", "piecesStyle", style); }, async loadPGN(pgn: string) { const game = new Game().loadPGN(pgn); @@ -126,13 +138,21 @@ const main = async () => { await player.load(game); }, async downloadImage() { - const data = await createImage(state.fen, state.board, 1024); + const data = await createImage( + state.fen, + state.pgn, + state.ply, + state.board, + state.game.picSize + ); download(data, "fen", "png"); }, }; // @ts-ignore window.handlers = handlers; + // @ts-ignore + window.state = state; /** * RENDER diff --git a/src/state.ts b/src/state.ts index 4fa9db2..f885eb9 100644 --- a/src/state.ts +++ b/src/state.ts @@ -1,3 +1,4 @@ +import isMobile from "is-mobile"; import { createStore } from "solid-js/store"; import { BoardConfig, GameConfig } from "./types"; @@ -32,6 +33,7 @@ export type State = { fen: string; moves: string[]; ply: number; + mobile: boolean; }; const initialState: State = { @@ -41,6 +43,7 @@ const initialState: State = { fen: "", moves: [], ply: 0, + mobile: isMobile(), }; const [state, setState] = createStore(initialState); diff --git a/src/types.ts b/src/types.ts index 24dca1a..90f7dd0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -131,14 +131,16 @@ export type BoardConfig = { flipped: boolean; }; +export type Size = "XS" | "S" | "M" | "L" | "XL"; + export type GameConfig = { titleScreen: boolean; fromPly: number | null; toPly: number | null; loop: boolean; format: "GIF" | "MP4" | "WebM"; - picSize: "XS" | "S" | "M" | "L" | "XL"; - animationSize: "XS" | "S" | "M" | "L" | "XL"; + picSize: Size; + animationSize: Size; }; export type MaterialCount = { diff --git a/src/ui/components/Share.tsx b/src/ui/components/Share.tsx index 4a06ce7..b697759 100644 --- a/src/ui/components/Share.tsx +++ b/src/ui/components/Share.tsx @@ -1,4 +1,4 @@ -import { Component, createSignal } from "solid-js"; +import { Component, createSignal, Show } from "solid-js"; import { Handlers } from "../../types"; import Scrollable from "./reusable/Scrollable"; import { state, setState } from "../../state"; @@ -83,60 +83,62 @@ const Share: Component<{ handlers: Handlers }> = (props) => { {copyId() === "fen-link" ? "Copied!" : "Copy link"} -

Image

- - - - - - + +

Image

+ + + + + + +

Game

@@ -149,88 +151,88 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
-
-

Animation

- - - - - - - - - - - -
+ +
+

Animation

+ + + + + + + + + +
+
); }; diff --git a/src/ui/components/sizeToPX.ts b/src/ui/components/sizeToPX.ts deleted file mode 100644 index 11b69ae..0000000 --- a/src/ui/components/sizeToPX.ts +++ /dev/null @@ -1,9 +0,0 @@ -const sizeToPX = { - XS: "256", - S: "512", - M: "720", - L: "1024", - XL: "1440", -}; - -export default sizeToPX; diff --git a/src/utils/download.ts b/src/utils/download.ts index 0f524be..c1f09bc 100644 --- a/src/utils/download.ts +++ b/src/utils/download.ts @@ -1,9 +1,10 @@ -const download = (data: string | Blob, name: string, ext: string) => { +const download = (data: string, name: string, ext: string) => { const url = typeof data === "string" ? data : URL.createObjectURL(data); const link = document.createElement("a"); link.href = url; link.download = `${name}_${Date.now()}.${ext}`; + link.target = "_blank"; link.click(); };