WIP
This commit is contained in:
@@ -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
40
src/state.ts
Normal 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 };
|
||||
@@ -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;
|
||||
|
||||
@@ -173,4 +173,5 @@ export type Handlers = {
|
||||
toggleExtraInfo(): void;
|
||||
flip(): void;
|
||||
togglePlay(): void;
|
||||
goto(ply: number): void;
|
||||
};
|
||||
|
||||
29
src/ui/App.tsx
Normal file
29
src/ui/App.tsx
Normal 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
35
src/ui/components/Controls.tsx
Normal file
35
src/ui/components/Controls.tsx
Normal 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;
|
||||
26
src/ui/components/Load.tsx
Normal file
26
src/ui/components/Load.tsx
Normal 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;
|
||||
37
src/ui/components/Moves.tsx
Normal file
37
src/ui/components/Moves.tsx
Normal 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;
|
||||
26
src/ui/components/load.css
Normal file
26
src/ui/components/load.css
Normal 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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user