WIP
This commit is contained in:
20
src/encoders/createImage.ts
Normal file
20
src/encoders/createImage.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { BoardConfig } from "../types";
|
||||||
|
import Board from "../board/Board";
|
||||||
|
import Game from "../game/Game";
|
||||||
|
|
||||||
|
const createImage = async (
|
||||||
|
fen: string,
|
||||||
|
boardConfig: BoardConfig,
|
||||||
|
size: number
|
||||||
|
) => {
|
||||||
|
const game = new Game().loadFEN(fen);
|
||||||
|
const board = new Board({ ...boardConfig, size });
|
||||||
|
|
||||||
|
const position = game.getPosition(0);
|
||||||
|
await board.frame(position, {});
|
||||||
|
board.render();
|
||||||
|
|
||||||
|
return board.toImgUrl();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createImage;
|
||||||
11
src/main.tsx
11
src/main.tsx
@@ -13,6 +13,8 @@ import { state, setState } from "./state";
|
|||||||
|
|
||||||
import { render } from "solid-js/web";
|
import { render } from "solid-js/web";
|
||||||
import App from "./ui/App";
|
import App from "./ui/App";
|
||||||
|
import download from "./utils/download";
|
||||||
|
import createImage from "./encoders/createImage";
|
||||||
|
|
||||||
const boardConfig: BoardConfig = {
|
const boardConfig: BoardConfig = {
|
||||||
size: 1024,
|
size: 1024,
|
||||||
@@ -34,7 +36,8 @@ const gameConfig: GameConfig = {
|
|||||||
toPly: null,
|
toPly: null,
|
||||||
loop: true,
|
loop: true,
|
||||||
format: "GIF",
|
format: "GIF",
|
||||||
size: "M",
|
picSize: "M",
|
||||||
|
animationSize: "M",
|
||||||
};
|
};
|
||||||
|
|
||||||
const createDownloadLink = async (pgn: string, boardConfig: BoardConfig) => {
|
const createDownloadLink = async (pgn: string, boardConfig: BoardConfig) => {
|
||||||
@@ -114,7 +117,7 @@ const main = async () => {
|
|||||||
},
|
},
|
||||||
async loadPGN(pgn: string) {
|
async loadPGN(pgn: string) {
|
||||||
const game = new Game().loadPGN(pgn);
|
const game = new Game().loadPGN(pgn);
|
||||||
setState({ pgn, fen: null, moves: game.getMoves() });
|
setState({ pgn, fen: "", moves: game.getMoves() });
|
||||||
await player.load(game);
|
await player.load(game);
|
||||||
},
|
},
|
||||||
async loadFEN(fen: string) {
|
async loadFEN(fen: string) {
|
||||||
@@ -122,6 +125,10 @@ const main = async () => {
|
|||||||
setState({ pgn: null, fen, moves: game.getMoves() });
|
setState({ pgn: null, fen, moves: game.getMoves() });
|
||||||
await player.load(game);
|
await player.load(game);
|
||||||
},
|
},
|
||||||
|
async downloadImage() {
|
||||||
|
const data = await createImage(state.fen, state.board, 1024);
|
||||||
|
download(data, "fen", "png");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ const gameConfig: GameConfig = {
|
|||||||
toPly: null,
|
toPly: null,
|
||||||
loop: true,
|
loop: true,
|
||||||
format: "GIF",
|
format: "GIF",
|
||||||
size: "M",
|
picSize: "M",
|
||||||
|
animationSize: "M",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ export type GameConfig = {
|
|||||||
toPly: number | null;
|
toPly: number | null;
|
||||||
loop: boolean;
|
loop: boolean;
|
||||||
format: "GIF" | "MP4" | "WebM";
|
format: "GIF" | "MP4" | "WebM";
|
||||||
size: "XS" | "S" | "M" | "L" | "XL";
|
picSize: "XS" | "S" | "M" | "L" | "XL";
|
||||||
|
animationSize: "XS" | "S" | "M" | "L" | "XL";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MaterialCount = {
|
export type MaterialCount = {
|
||||||
@@ -203,4 +204,5 @@ export type Handlers = {
|
|||||||
changePiecesStyle: (style: PiecesStyle) => void;
|
changePiecesStyle: (style: PiecesStyle) => void;
|
||||||
loadPGN: (pgn: string) => Promise<void>;
|
loadPGN: (pgn: string) => Promise<void>;
|
||||||
loadFEN: (fen: string) => Promise<void>;
|
loadFEN: (fen: string) => Promise<void>;
|
||||||
|
downloadImage: () => void;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ h2 {
|
|||||||
margin: 25px 0 10px 0;
|
margin: 25px 0 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #aaa;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
margin: 15px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
background-color: #191d24;
|
background-color: #191d24;
|
||||||
/* background-image: url(src/ui/img/pattern.png); */
|
/* background-image: url(src/ui/img/pattern.png); */
|
||||||
|
|||||||
@@ -40,3 +40,8 @@
|
|||||||
.share__btn {
|
.share__btn {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header--first {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
import { Component } from "solid-js";
|
import { Component, createSignal } from "solid-js";
|
||||||
import { Handlers } from "../../types";
|
import { Handlers } from "../../types";
|
||||||
import Scrollable from "./reusable/Scrollable";
|
import Scrollable from "./reusable/Scrollable";
|
||||||
import { state, setState } from "../../state";
|
import { state, setState } from "../../state";
|
||||||
import "./Share.css";
|
import "./Share.css";
|
||||||
|
|
||||||
const Share: Component<{ handlers: Handlers }> = (props) => {
|
const Share: Component<{ handlers: Handlers }> = (props) => {
|
||||||
|
const [copyId, setCopyId] = createSignal("");
|
||||||
|
|
||||||
|
const blinkCopy = (id: string) => {
|
||||||
|
setCopyId(id);
|
||||||
|
setTimeout(() => setCopyId(""), 1000);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scrollable class="share">
|
<Scrollable class="share">
|
||||||
<div className="share__view">
|
<div className="share__view">
|
||||||
<h2>Board options</h2>
|
<h2 class="header--first">Board options</h2>
|
||||||
<button
|
<button
|
||||||
class="controls__button controls__button--first"
|
class="controls__button controls__button--first"
|
||||||
onClick={props.handlers.flip}
|
onClick={props.handlers.flip}
|
||||||
@@ -56,10 +63,80 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="double">
|
<div class="double">
|
||||||
<button class="share__btn share__btn--left">Copy FEN</button>
|
<button
|
||||||
<button class="share__btn share__btn--right">Copy link</button>
|
class="share__btn share__btn--left"
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(state.fen);
|
||||||
|
blinkCopy("fen");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{copyId() === "fen" ? "Copied!" : "Copy FEN"}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="share__btn share__btn--right"
|
||||||
|
onClick={() => {
|
||||||
|
const link = `${location.origin}/#v1/fen/${encodeURI(state.fen)}`;
|
||||||
|
navigator.clipboard.writeText(link);
|
||||||
|
blinkCopy("fen-link");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{copyId() === "fen-link" ? "Copied!" : "Copy link"}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="share__btn">Save as image</button>
|
<h3>Image</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
|
||||||
|
class="share__btn"
|
||||||
|
onClick={() => props.handlers.downloadImage()}
|
||||||
|
>
|
||||||
|
Save as image
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="share__pgn">
|
<div class="share__pgn">
|
||||||
<h2>Game</h2>
|
<h2>Game</h2>
|
||||||
@@ -73,41 +150,41 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="share__animation">
|
<div class="share__animation">
|
||||||
<h2>Animation</h2>
|
<h3>Animation</h3>
|
||||||
<button
|
<button
|
||||||
classList={{
|
classList={{
|
||||||
share__size: true,
|
share__size: true,
|
||||||
"share__size--first": true,
|
"share__size--first": true,
|
||||||
"share__size--active": state.game.size === "XS",
|
"share__size--active": state.game.picSize === "XS",
|
||||||
}}
|
}}
|
||||||
onClick={() => setState("game", "size", "XS")}
|
onClick={() => setState("game", "picSize", "XS")}
|
||||||
>
|
>
|
||||||
XS
|
XS
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
classList={{
|
classList={{
|
||||||
share__size: true,
|
share__size: true,
|
||||||
"share__size--active": state.game.size === "S",
|
"share__size--active": state.game.picSize === "S",
|
||||||
}}
|
}}
|
||||||
onClick={() => setState("game", "size", "S")}
|
onClick={() => setState("game", "picSize", "S")}
|
||||||
>
|
>
|
||||||
S
|
S
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
classList={{
|
classList={{
|
||||||
share__size: true,
|
share__size: true,
|
||||||
"share__size--active": state.game.size === "M",
|
"share__size--active": state.game.picSize === "M",
|
||||||
}}
|
}}
|
||||||
onClick={() => setState("game", "size", "M")}
|
onClick={() => setState("game", "picSize", "M")}
|
||||||
>
|
>
|
||||||
M
|
M
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
classList={{
|
classList={{
|
||||||
share__size: true,
|
share__size: true,
|
||||||
"share__size--active": state.game.size === "L",
|
"share__size--active": state.game.picSize === "L",
|
||||||
}}
|
}}
|
||||||
onClick={() => setState("game", "size", "L")}
|
onClick={() => setState("game", "picSize", "L")}
|
||||||
>
|
>
|
||||||
L
|
L
|
||||||
</button>
|
</button>
|
||||||
@@ -115,9 +192,9 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
classList={{
|
classList={{
|
||||||
share__size: true,
|
share__size: true,
|
||||||
"share__size--last": true,
|
"share__size--last": true,
|
||||||
"share__size--active": state.game.size === "XL",
|
"share__size--active": state.game.picSize === "XL",
|
||||||
}}
|
}}
|
||||||
onClick={() => setState("game", "size", "XL")}
|
onClick={() => setState("game", "picSize", "XL")}
|
||||||
>
|
>
|
||||||
XL
|
XL
|
||||||
</button>
|
</button>
|
||||||
@@ -152,7 +229,7 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
WebM
|
WebM
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="share__create-animation">GENERATE</button>
|
<button class="share__create-animation">Save animation</button>
|
||||||
</div>
|
</div>
|
||||||
</Scrollable>
|
</Scrollable>
|
||||||
);
|
);
|
||||||
|
|||||||
9
src/ui/components/sizeToPX.ts
Normal file
9
src/ui/components/sizeToPX.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const sizeToPX = {
|
||||||
|
XS: "256",
|
||||||
|
S: "512",
|
||||||
|
M: "720",
|
||||||
|
L: "1024",
|
||||||
|
XL: "1440",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default sizeToPX;
|
||||||
10
src/utils/download.ts
Normal file
10
src/utils/download.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const download = (data: string | Blob, 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.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default download;
|
||||||
Reference in New Issue
Block a user