This commit is contained in:
Maciej Caderek
2022-02-14 00:00:41 +01:00
parent 6274236ac7
commit e0b79a7071
26 changed files with 608 additions and 358 deletions

View File

@@ -22,7 +22,21 @@ body {
font-family: Ubuntu, sans-serif;
}
button {
.upload {
visibility: hidden;
padding: 0;
}
.upload::before {
content: "UPLOAD PGN FILE";
visibility: visible;
display: inline-block;
text-align: center;
box-sizing: border-box;
}
button,
.upload::before {
padding: 10px;
font-family: "Ubuntu";
font-size: 1.5rem;
@@ -32,7 +46,8 @@ button {
width: 100%;
}
button:hover {
button:hover,
.upload:hover::before {
background: rgb(0, 207, 162);
cursor: pointer;
}
@@ -69,6 +84,11 @@ h3 {
margin: 15px 0 10px 0;
}
hr {
margin-top: 20px;
border-top: solid 1px #ffffff22;
}
.dark {
background-color: #191d24;
/* background-image: url(src/ui/img/pattern.png); */

View File

@@ -25,7 +25,7 @@ const prepareBoards = async () => {
for (const [key, style] of Object.entries(styles) as [BoardStyle, Style][]) {
await board.updateConfig({ boardStyle: key });
await board.frame(null, {});
await board.frame(null);
board.render();
boards.push({
key,
@@ -51,12 +51,12 @@ const Boards: Component<{ handlers: Handlers }> = (props) => {
<img
class={
"boards__ico" +
(state.board.boardStyle === board.key
(state.boardConfig.boardStyle === board.key
? " boards__ico--active"
: "")
}
onClick={() => {
setState("board", "boardStyle", board.key);
setState("boardConfig", "boardStyle", board.key);
props.handlers.changeBoardStyle(board.key);
}}
src={board.img}

View File

@@ -20,7 +20,7 @@ const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
}
onClick={() => setTab("moves")}
>
MOVES
GAME
</button>
<button
class={

View File

@@ -28,3 +28,16 @@
.load__pgn-btn {
width: 100%;
}
.load__pgn-file {
margin-top: 20px;
}
.load__pgn-file-info {
font-size: 1.5rem;
}
.load__pgn-file-info p {
margin-top: 10px;
color: #677794;
}

View File

@@ -1,5 +1,6 @@
import { Component, createSignal } from "solid-js";
import { Handlers } from "../../types";
import readFile from "../../utils/readFile";
import "./Load.css";
const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
@@ -22,12 +23,15 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
<button
class="load__fen-btn"
onClick={() => {
props.handlers.loadFEN(fen());
setFEN("");
if (fen()) {
props.handlers.loadFEN(fen());
setFEN("");
}
}}
>
LOAD FEN
</button>
<hr />
<textarea
class="load__pgn-input"
name="load-pgn"
@@ -39,13 +43,33 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
<button
class="load__pgn-btn"
onClick={() => {
props.handlers.loadPGN(pgn());
setPGN("");
props.showMoves();
if (pgn()) {
props.handlers.loadPGN(pgn());
setPGN("");
props.showMoves();
}
}}
>
LOAD PGN
</button>
<hr />
<input
class="upload load__pgn-file"
type="file"
accept="application/vnd.chess-pgn,application/x-chess-pgn,.pgn"
onChange={async (e) => {
const target = e.target as HTMLInputElement;
if (target?.files && target.files.length > 0) {
const content = await readFile(target.files[0]);
props.handlers.loadPGN(content);
props.showMoves();
}
}}
></input>
<div className="load__pgn-file-info">
<p>or</p>
<p>drop the PGN file anywhere on the page</p>
</div>
</div>
);
};

View File

@@ -1,4 +1,4 @@
import { Component, For } from "solid-js";
import { Component, For, createEffect } from "solid-js";
import chunk_ from "@arrows/array/chunk_";
import { Handlers } from "../../types";
import Scrollable from "./reusable/Scrollable";
@@ -8,6 +8,10 @@ import { state } from "../../state";
const Moves: Component<{ moves: readonly string[]; handlers: Handlers }> = (
props
) => {
createEffect(() => {
document.querySelector(`[data-ply="${state.ply}"]`)?.scrollIntoView();
});
return (
<Scrollable class="moves">
<For each={chunk_(2, props.moves as string[])}>
@@ -23,6 +27,7 @@ const Moves: Component<{ moves: readonly string[]; handlers: Handlers }> = (
"move__ply--current": state.ply === i() * 2 + 1,
}}
onClick={() => props.handlers.goto(i() * 2 + 1)}
data-ply={i() * 2 + 1}
>
{white}
</span>
@@ -32,6 +37,7 @@ const Moves: Component<{ moves: readonly string[]; handlers: Handlers }> = (
"move__ply--current": state.ply === i() * 2 + 2,
}}
onClick={() => props.handlers.goto(i() * 2 + 2)}
data-ply={i() * 2 + 2}
>
{black}
</span>

View File

@@ -19,12 +19,12 @@ const Pieces: Component<{ handlers: Handlers }> = (props) => {
<img
class={
"pieces__ico" +
(state.board.piecesStyle === item.key
(state.boardConfig.piecesStyle === item.key
? " pieces__ico--active"
: "")
}
onClick={() => {
setState("board", "piecesStyle", item.key);
setState("boardConfig", "piecesStyle", item.key);
props.handlers.changePiecesStyle(item.key);
}}
src={item.img}
@@ -97,7 +97,7 @@ export default Pieces;
// ? " boards__ico--active"
// : "")
// }
// onClick={() => setState("board", "boardStyle", board.key)}
// onClick={() => setState("boardConfig", "boardStyle", board.key)}
// src={board.img}
// title={board.name}
// />

View File

@@ -45,3 +45,40 @@
margin-top: 0;
margin-bottom: 25px;
}
.options__button {
margin: 3px;
padding: 5px;
font-size: 3rem;
background: rgb(0, 173, 136);
text-align: center;
border-radius: 5px;
width: 44px;
height: 44px;
opacity: 0.5;
}
.options__button--active {
opacity: 1;
}
.options__button:hover {
background: rgb(0, 207, 162);
cursor: pointer;
}
.options__button--last {
margin-right: 0px;
}
.options__button--first {
margin-left: 0px;
}
.rotatable {
transition: transform 0.3s;
}
.rotated {
transform: rotate(180deg);
}

View File

@@ -3,6 +3,7 @@ import { Handlers } from "../../types";
import Scrollable from "./reusable/Scrollable";
import { state, setState } from "../../state";
import "./Share.css";
import download from "../../utils/download";
const Share: Component<{ handlers: Handlers }> = (props) => {
const [copyId, setCopyId] = createSignal("");
@@ -17,41 +18,66 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
<div className="share__view">
<h2 class="header--first">Board options</h2>
<button
class="controls__button controls__button--first"
onClick={props.handlers.flip}
title="FLIP"
classList={{
options__button: true,
"options__button--first": true,
"options__button--active": true,
}}
>
<i class="las la-sync"></i>
<i
classList={{
rotated: state.boardConfig.flipped,
las: true,
"la-sync": true,
rotatable: true,
}}
></i>
</button>
<button
class="controls__button"
classList={{
options__button: true,
"options__button--active": state.boardConfig.showBorder,
}}
onClick={props.handlers.toggleBorder}
title="BORDER"
>
<i class="las la-expand"></i>
</button>
<button
class="controls__button"
classList={{
options__button: true,
"options__button--active": state.boardConfig.showExtraInfo,
}}
onClick={props.handlers.toggleExtraInfo}
title="EXTRA INFO"
>
<i class="las la-info-circle"></i>
</button>
<button
class="controls__button"
onClick={props.handlers.toggleExtraInfo}
title="INCLUDE HEADER"
classList={{
options__button: true,
"options__button--active": state.gameConfig.titleScreen,
}}
onClick={props.handlers.toggleTitleScreen}
title="TITLE SCREEN"
>
<i class="las la-heading"></i>
</button>
<button
class="controls__button controls__button--last"
onClick={props.handlers.toggleExtraInfo}
classList={{
options__button: true,
"options__button--last": true,
"options__button--active": state.boardConfig.anonymous,
}}
onClick={props.handlers.toggleAnonymous}
title="ANONYMOUS"
>
<i class="las la-user-secret"></i>
</button>
</div>
<hr />
<div className="share__fen">
<h2>Current position</h2>
<input
@@ -89,36 +115,36 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
classList={{
share__size: true,
"share__size--first": true,
"share__size--active": state.game.picSize === "XS",
"share__size--active": state.gameConfig.picSize === "XS",
}}
onClick={() => setState("game", "picSize", "XS")}
onClick={() => setState("gameConfig", "picSize", "XS")}
>
XS
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.picSize === "S",
"share__size--active": state.gameConfig.picSize === "S",
}}
onClick={() => setState("game", "picSize", "S")}
onClick={() => setState("gameConfig", "picSize", "S")}
>
S
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.picSize === "M",
"share__size--active": state.gameConfig.picSize === "M",
}}
onClick={() => setState("game", "picSize", "M")}
onClick={() => setState("gameConfig", "picSize", "M")}
>
M
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.picSize === "L",
"share__size--active": state.gameConfig.picSize === "L",
}}
onClick={() => setState("game", "picSize", "L")}
onClick={() => setState("gameConfig", "picSize", "L")}
>
L
</button>
@@ -126,9 +152,9 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
classList={{
share__size: true,
"share__size--last": true,
"share__size--active": state.game.picSize === "XL",
"share__size--active": state.gameConfig.picSize === "XL",
}}
onClick={() => setState("game", "picSize", "XL")}
onClick={() => setState("gameConfig", "picSize", "XL")}
>
XL
</button>
@@ -140,98 +166,156 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
</button>
</Show>
</div>
<div class="share__pgn">
<h2>Game</h2>
<div class="double">
<button class="share__btn">Copy PGN</button>
<button class="share__btn">Copy link</button>
</div>
<div class="double">
<button class="share__btn">Export PGN</button>
<button class="share__btn">Copy markdown</button>
</div>
</div>
<Show when={!state.mobile}>
<div class="share__animation">
<h3>Animation</h3>
<button
classList={{
share__size: true,
"share__size--first": true,
"share__size--active": state.game.animationSize === "XS",
}}
onClick={() => setState("game", "animationSize", "XS")}
>
XS
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.animationSize === "S",
}}
onClick={() => setState("game", "animationSize", "S")}
>
S
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.animationSize === "M",
}}
onClick={() => setState("game", "animationSize", "M")}
>
M
</button>
<button
classList={{
share__size: true,
"share__size--active": state.game.animationSize === "L",
}}
onClick={() => setState("game", "animationSize", "L")}
>
L
</button>
<button
classList={{
share__size: true,
"share__size--last": true,
"share__size--active": state.game.animationSize === "XL",
}}
onClick={() => setState("game", "animationSize", "XL")}
>
XL
</button>
<button
classList={{
share__format: true,
"share__format--first": true,
"share__format--active": state.game.format === "GIF",
}}
onClick={() => setState("game", "format", "GIF")}
>
GIF
</button>
<button
classList={{
share__format: true,
"share__format--active": state.game.format === "MP4",
}}
onClick={() => setState("game", "format", "MP4")}
>
MP4
</button>
<button
classList={{
share__format: true,
"share__format--last": true,
"share__format--active": state.game.format === "WebM",
}}
onClick={() => setState("game", "format", "WebM")}
>
WebM
</button>
<button class="share__create-animation">Save animation</button>
<Show when={state.pgn}>
<hr />
<div class="share__pgn">
<h2>Game</h2>
<div class="double">
<button
class="share__btn"
onClick={() => {
navigator.clipboard.writeText(state.pgn);
blinkCopy("pgn");
}}
>
{copyId() === "pgn" ? "Copied!" : "Copy PGN"}
</button>
<button
class="share__btn"
onClick={() => {
navigator.clipboard.writeText(window.location.href);
blinkCopy("pgn-link");
}}
>
{copyId() === "pgn-link" ? "Copied!" : "Copy link"}
</button>
</div>
<div class="double">
<button
class="share__btn"
onClick={() => {
const data = new Blob([state.pgn], {
type: "application/vnd.chess-pgn;charset=utf-8",
});
download(data, "pgn", "pgn");
}}
>
Export PGN
</button>
<button
class="share__btn"
onClick={() => {
const header = state.game.header;
const w = state.boardConfig.anonymous
? "Anonymous"
: header.WhitePretty;
const b = state.boardConfig.anonymous
? "Anonymous"
: header.BlackPretty;
const title =
`${w} vs ${b}` +
(header.Event ? ` | ${header.Event}` : "") +
(header.Round ? `, Round ${header.Round}` : "") +
(header.DatePretty ? ` | ${header.DatePretty}` : "");
const md = `[${title}](${window.location.href})`;
navigator.clipboard.writeText(md);
blinkCopy("markdown");
}}
>
{copyId() === "markdown" ? "Copied!" : "Copy markdown"}
</button>
</div>
</div>
<Show when={!state.mobile}>
<div class="share__animation">
<h3>Animation</h3>
<button
classList={{
share__size: true,
"share__size--first": true,
"share__size--active": state.gameConfig.animationSize === "XS",
}}
onClick={() => setState("gameConfig", "animationSize", "XS")}
>
XS
</button>
<button
classList={{
share__size: true,
"share__size--active": state.gameConfig.animationSize === "S",
}}
onClick={() => setState("gameConfig", "animationSize", "S")}
>
S
</button>
<button
classList={{
share__size: true,
"share__size--active": state.gameConfig.animationSize === "M",
}}
onClick={() => setState("gameConfig", "animationSize", "M")}
>
M
</button>
<button
classList={{
share__size: true,
"share__size--active": state.gameConfig.animationSize === "L",
}}
onClick={() => setState("gameConfig", "animationSize", "L")}
>
L
</button>
<button
classList={{
share__size: true,
"share__size--last": true,
"share__size--active": state.gameConfig.animationSize === "XL",
}}
onClick={() => setState("gameConfig", "animationSize", "XL")}
>
XL
</button>
<button
classList={{
share__format: true,
"share__format--first": true,
"share__format--active": state.gameConfig.format === "GIF",
}}
onClick={() => setState("gameConfig", "format", "GIF")}
>
GIF
</button>
<button
classList={{
share__format: true,
"share__format--active": state.gameConfig.format === "MP4",
}}
onClick={() => setState("gameConfig", "format", "MP4")}
>
MP4
</button>
<button
classList={{
share__format: true,
"share__format--last": true,
"share__format--active": state.gameConfig.format === "WebM",
}}
onClick={() => setState("gameConfig", "format", "WebM")}
>
WebM
</button>
<button
class="share__create-animation"
onClick={() => props.handlers.downloadAnimation()}
>
Save animation
</button>
</div>
</Show>
</Show>
</Scrollable>
);