This commit is contained in:
Maciej Caderek
2022-02-07 18:49:17 +01:00
parent 4fa2ba1fb9
commit f2d6c080d4
20 changed files with 1749 additions and 127 deletions

View File

@@ -1,5 +1,4 @@
import { BoardConfig, GameConfig } from "./types";
import "./style.css";
import Board from "./board/Board";
import Game from "./game/Game";
import styles from "./board/styles-board";
@@ -9,16 +8,19 @@ import createAnimation from "./encoders/createAnimation";
import WebFont from "webfontloader";
import Player from "./player/Player";
import * as Hammer from "hammerjs";
import Moves from "./ui/Moves";
import Controls from "./ui/Controls";
// import Moves from "./ui/Moves";
// import Controls from "./ui/Controls";
import { state, setState } from "./state";
import { render } from "solid-js/web";
import App from "./ui/App";
const $board = document.querySelector<HTMLImageElement>("#board");
const $moves = document.querySelector<HTMLImageElement>("#moves");
const $controls = document.querySelector<HTMLImageElement>("#controls");
const boardConfig: BoardConfig = {
size: 1024,
boardStyle: styles.lila,
boardStyle: styles.calm,
piecesStyle: "tatiana",
showBorder: true,
showExtraInfo: true,
@@ -57,14 +59,16 @@ const main = async () => {
// const pgn = pgns[2];
const board = new Board(boardConfig);
$board?.appendChild(board.canvas);
// const interval = 1000;
// play(board, gameConfig, pgn, interval);
const player = new Player(board, gameConfig);
const game = new Game().loadPGN(pgn);
console.log(game.getMoves());
setState({ moves: game.getMoves() });
const handlers = {
prev() {
player.pause();
@@ -101,10 +105,26 @@ const main = async () => {
togglePlay() {
player.playing ? player.pause() : player.play();
},
goto(ply: number) {
player.pause();
player.goto(ply);
},
};
const moves = new Moves($moves as HTMLElement, player).load(game.getMoves());
const controls = new Controls($controls as HTMLElement, handlers).load();
/**
* RENDER
**/
render(
() => <App handlers={handlers} state={state} />,
document.getElementById("root") as HTMLElement
);
const $board = document.querySelector<HTMLImageElement>("#board");
console.log({ $board });
$board?.appendChild(board.canvas);
// const moves = new Moves($moves as HTMLElement, player).load(game.getMoves());
// const controls = new Controls($controls as HTMLElement, handlers).load();
await player.load(game);
@@ -112,8 +132,8 @@ const main = async () => {
window.load = async (pgn: string) => {
const game = new Game().loadPGN(pgn);
await player.load(game);
moves.load(game.getMoves());
controls.load();
// moves.load(game.getMoves());
// controls.load();
};
document.addEventListener(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

40
src/state.ts Normal file
View File

@@ -0,0 +1,40 @@
import { createStore } from "solid-js/store";
import { BoardConfig, GameConfig } from "./types";
import styles from "./board/styles-board";
const boardConfig: BoardConfig = {
size: 1024,
boardStyle: styles.calm,
piecesStyle: "tatiana",
showBorder: true,
showExtraInfo: true,
showMaterial: true,
showMoveIndicator: true,
showChecks: true,
showCoords: true,
flipped: false,
};
const gameConfig: GameConfig = {
titleScreen: true,
fromPly: null,
toPly: null,
loop: true,
};
export type State = {
board: BoardConfig;
game: GameConfig;
moves: string[];
};
const initialState: State = {
board: boardConfig,
game: gameConfig,
moves: [],
};
const [state, setState] = createStore(initialState);
export { state, setState };

View File

@@ -21,28 +21,6 @@ const pgns = [
Qc4 31. Qxf6 Kxa3 32. Qxa6+ Kxb4 33. c3+ Kxc3 34. Qa1+ Kd2
35. Qb2+ Kd1 36. Bf1 Rd2 37. Rd7 Rxd7 38. Bxc4 bxc4 39. Qxh8
Rd3 40. Qa8 c3 41. Qa4+ Ke1 42. f4 f5 43. Kc1 Rd2 44. Qa7 1-0`,
`[Black "caderek"]
[BlackElo "1325"]
[Date "2022.01.28"]
[Event "Rated Bullet game"]
[Result "0-1"]
[Site "https://lichess.org/tfEplTYl"]
[White "PHOS747"]
[WhiteElo "1335"]
1. e4 c5 2. Bc4 Nc6 3. Qf3 Ne5 4. Qc3 Nxc4 5. Qxc4 b6 6. Nh3 e6 7. Ng5 Qxg5 8. d4 Qxc1+ 9. Ke2 Qxh1 10. f4 Qxg2+ 11. Ke3 Qxh2 12. Nd2 Qh3+ 13. Nf3 Nf6 14. e5 Ng4+ 15. Ke4 Bb7+ 16. Kd3 Qxf3+ 17. Kd2 Qe3+ 18. Kd1 Nf2# 0-1`,
`[Black "Grandelius, Nils"]
[BlackElo "2617"]
[Date "2021.11.16"]
[Event "Casual Blitz game"]
[Result "0-1"]
[Site "https://youtu.be/QApxkK-cRxo"]
[White "Cramling Bellon, Anna"]
[WhiteElo "1905"]
1. d4 Nf6 2. c4 c5 3. d5 b5 4. cxb5 a6 5. Nc3 axb5 6. e4 b4 7. Nb5 d6 8. Bc4 g6 9. e5 Ng4 10. e6 Ne5 11. exf7+ Nxf7 12. Nf3 Bg7 13. O-O O-O 14. Re1 Bg4 15. h3 Bxf3 16. Qxf3 Ne5 17. Qb3 Nbd7 18. Bg5 Nb6 19. Bf1 Rf5 20. Bh4 Qf8 21. a4 bxa3 22. Rxa3 Rxa3 23. Qxa3 Rf3 24. Bxe7 Qxe7 25. gxf3 Qg5+ 26. Kh1 Qh4 27. Qa7 Qxf2 28. Qb8+ Bf8 29. Ra1 Nxf3 30. Bg2 Ne1 31. Rxe1 Qxe1+ 32. Kh2 Qe5+ 33. Kg1 Nc4 34. Nc7 Qxb2 35. Qe8 Qf6 36. Ne6 Ne5 37. Qb8 c4 38. Qb4 Qf2+ 39. Kh2 Nf3+ 40. Kh1 Qg1#`,
];
export default pgns;

View File

@@ -173,4 +173,5 @@ export type Handlers = {
toggleExtraInfo(): void;
flip(): void;
togglePlay(): void;
goto(ply: number): void;
};

29
src/ui/App.tsx Normal file
View File

@@ -0,0 +1,29 @@
import type { Component } from "solid-js";
import type { DeepReadonly } from "solid-js/store";
import Moves from "./components/Moves";
import Controls from "./components/Controls";
import Load from "./components/Load";
import { Handlers } from "../types";
import { State } from "../state";
import "./app.css";
const App: Component<{ handlers: Handlers; state: DeepReadonly<State> }> = (
props
) => {
return (
<div class="layout">
<div id="setup" class="setup-box"></div>
<div id="board" class="board-box"></div>
<div id="controls" class="controls-box">
<Controls handlers={props.handlers}></Controls>
</div>
<div id="moves" class="moves-box">
{/* <Moves moves={props.state.moves} handlers={props.handlers}></Moves> */}
<Load></Load>
</div>
</div>
);
};
export default App;

View File

@@ -1,38 +0,0 @@
import { Handlers } from "./../types";
import { html } from "common-tags";
class Controls {
constructor(private element: HTMLElement, handlers: Handlers) {
this.element.addEventListener("click", (e) => {
const target = e.target as HTMLElement;
if (target?.dataset?.type === "control") {
const action = target?.dataset?.action;
console.log(action);
if (action && handlers.hasOwnProperty(action)) {
// @ts-ignore
handlers[action]();
}
}
});
}
load() {
const content = html`<div class="controls">
<button data-type="control" data-action="first">FIRST</button>
<button data-type="control" data-action="prev">PREV</button>
<button data-type="control" data-action="togglePlay">PLAY/PAUSE</button>
<button data-type="control" data-action="next">NEXT</button>
<button data-type="control" data-action="last">LAST</button>
<button data-type="control" data-action="flip">FLIP</button>
<button data-type="control" data-action="toggleBorder">TOGGLE BORDER</button>
<button data-type="control" data-action="toggleExtraInfo">TOGGLE EXTRA INFO</button>
</ul> `;
this.element.innerHTML = content;
return this;
}
}
export default Controls;

View File

@@ -1,36 +0,0 @@
import { html } from "common-tags";
import Player from "../player/Player";
import chunk_ from "@arrows/array/chunk_";
class Moves {
constructor(private element: HTMLElement, private player: Player) {
this.element.addEventListener("click", (e) => {
const target = e.target as HTMLElement;
if (target?.dataset?.type === "ply") {
const ply = Number(target?.dataset?.ply);
this.player.goto(ply);
}
});
}
load(moves: string[]) {
const items = chunk_(2, moves).map(
([white, black], i) =>
html`<p>
${i + 1}. <span data-type="ply" data-ply=${i * 2 + 1}>${white}</span>
<span data-type="ply" data-ply=${i * 2 + 2}>${black}</span>
</p>`
);
const content = html`<div class="moves">
${items.join("\n")}
</ul> `;
this.element.innerHTML = content;
return this;
}
}
export default Moves;

View File

@@ -7,6 +7,11 @@
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 10px;
}
body {
@@ -17,12 +22,14 @@ body {
.dark {
background-color: #191d24;
background-image: url(pattern.png);
background-image: url(src/ui/img/pattern.png);
color: #ddd;
}
.light {
background-color: #cfcfcf;
background-image: url(pattern-light.png);
background-image: url(src/ui/img/pattern-light.png);
color: #222;
}
.board {
@@ -47,29 +54,51 @@ body {
}
.moves-box {
background: rgba(255, 192, 203, 0.5);
/* background: rgba(255, 192, 203, 0.1); */
height: 85vh;
grid-area: moves;
}
.board-box {
background: rgba(255, 166, 0, 0.5);
/* background: rgba(255, 166, 0, 0.1); */
height: 100vh;
grid-area: board;
}
.setup-box {
background: rgba(135, 207, 235, 0.5);
/* background: rgba(135, 207, 235, 0.1); */
height: 100vh;
grid-area: setup;
}
.controls-box {
background: rgba(0, 255, 0, 0.5);
/* background: rgba(0, 255, 0, 0.1); */
height: 15vh;
grid-area: controls;
}
.controls__button {
margin: 5px;
padding: 5px;
cursor: pointer;
}
.moves {
padding: 20px;
}
.move {
display: inline-block;
width: 50%;
min-width: 150px;
text-align: left;
}
.ply {
padding-left: 10px;
cursor: pointer;
}
@media screen and (max-width: 1024px) {
.layout {
grid-template-columns: 1fr;

View File

@@ -0,0 +1,35 @@
import { Component } from "solid-js";
import { Handlers } from "../../types";
const Controls: Component<{ handlers: Handlers }> = (props) => {
return (
<div class="controls">
<button class="controls__button" onClick={props.handlers.first}>
FIRST
</button>
<button class="controls__button" onClick={props.handlers.prev}>
PREV
</button>
<button class="controls__button" onClick={props.handlers.togglePlay}>
PLAY/PAUSE
</button>
<button class="controls__button" onClick={props.handlers.next}>
NEXT
</button>
<button class="controls__button" onClick={props.handlers.last}>
LAST
</button>
<button class="controls__button" onClick={props.handlers.flip}>
FLIP
</button>
<button class="controls__button" onClick={props.handlers.toggleBorder}>
TOGGLE BORDER
</button>
<button class="controls__button" onClick={props.handlers.toggleExtraInfo}>
TOGGLE EXTRA INFO
</button>
</div>
);
};
export default Controls;

View File

@@ -0,0 +1,26 @@
import { Component, For } from "solid-js";
import chunk_ from "@arrows/array/chunk_";
import { Handlers } from "../../types";
import "./load.css";
const Load: Component<{}> = (props) => {
return (
<div class="load">
<input
class="load__fen-input"
type="text"
name="load-fen"
placeholder="PASTE FEN..."
/>
<button class="load__fen-btn">LOAD FEN</button>
<textarea
class="load__pgn-input"
name="load-pgn"
placeholder="PASTE PGN..."
></textarea>
<button class="load__pgn-btn">LOAD PGN</button>
</div>
);
};
export default Load;

View File

@@ -0,0 +1,37 @@
import { Component, For } from "solid-js";
import chunk_ from "@arrows/array/chunk_";
import { Handlers } from "../../types";
const Moves: Component<{ moves: readonly string[]; handlers: Handlers }> = (
props
) => {
return (
<div class="moves">
<For each={chunk_(2, props.moves as string[])}>
{(move, i) => {
const [white, black] = move as [string, string];
return (
<p class="move">
{i() + 1}.
<span
class="ply"
onClick={() => props.handlers.goto(i() * 2 + 1)}
>
{white}
</span>
<span
class="ply"
onClick={() => props.handlers.goto(i() * 2 + 2)}
>
{black}
</span>
</p>
);
}}
</For>
</div>
);
};
export default Moves;

View File

@@ -0,0 +1,26 @@
.load {
background: black;
padding: 20px;
}
.load__fen-input {
width: 100%;
padding: 10px;
font-family: "Fira Mono";
font-size: 1.4rem;
}
.load__pgn-input {
width: 100%;
padding: 10px;
font-family: "Fira Mono";
font-size: 1.4rem;
}
.load__fen-btn,
.load__pgn-btn {
width: 100%;
padding: 10px;
font-family: "Fira Mono";
font-size: 1.4rem;
}

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB