WIP
This commit is contained in:
@@ -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); */
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -20,7 +20,7 @@ const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
||||
}
|
||||
onClick={() => setTab("moves")}
|
||||
>
|
||||
MOVES
|
||||
GAME
|
||||
</button>
|
||||
<button
|
||||
class={
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
// />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user