This commit is contained in:
Maciej Caderek
2022-02-14 17:46:14 +01:00
parent e0b79a7071
commit 3e20babe24
8 changed files with 90 additions and 17 deletions

View File

@@ -0,0 +1,38 @@
type Result =
| { error: false; pgn: string; side: "w" | "b" }
| { error: true; errorType: "INCORRECT_LINK" | "SERVER_ERROR" };
const importFromLichess = async (link: string): Promise<Result> => {
const [first, second] = link
.replace(/^https:\/\/(www\.)*lichess\.org\/*/, "")
.split("/")
.map((x) => x.trim());
if (/^(([a-z0-9]{8})|([a-z0-9]{12}))$/i.test(first)) {
const id = first.slice(0, 8);
const res = await fetch(
`https://lichess.org/game/export/${id}?evals=0&clocks=0`
);
if (!String(res.status).startsWith("2")) {
return { error: true, errorType: "SERVER_ERROR" };
}
const pgn = await res.text();
return { error: false, pgn, side: second === "black" ? "b" : "w" };
}
return { error: true, errorType: "INCORRECT_LINK" };
};
const importFromLink = async (link: string): Promise<Result> => {
if (/^https:\/\/(www\.)*lichess\.org/.test(link)) {
return importFromLichess(link);
}
return { error: true, errorType: "INCORRECT_LINK" };
};
export default importFromLink;

View File

@@ -17,6 +17,7 @@ import readFile from "./utils/readFile";
import download from "./utils/download";
import { compressPGN } from "./game/PGNHelpers";
import extractUrlData from "./persistance/extractUrlData";
import importFromLink from "./imports/importFromLink";
const main = async () => {
const board = new Board(state.boardConfig);
@@ -101,12 +102,22 @@ const main = async () => {
window.location.hash = `v1/pgn/${compressPGN(game.pgn)}`;
await player.load(game);
setState("activeTab", "game");
},
async loadFEN(fen: string) {
const game = new Game().loadFEN(fen);
setState({ pgn: "", fen, moves: game.getMoves(), ply: 0, game });
await player.load(game);
},
async importPGN(link: string) {
const result = await importFromLink(link);
if (result.error) {
return;
}
await this.loadPGN(result.pgn);
},
async downloadImage() {
const data = await createImage(
state.fen,

View File

@@ -37,6 +37,7 @@ export type State = {
moves: string[];
ply: number;
mobile: boolean;
activeTab: "game" | "load";
};
const initialState: State = {
@@ -48,6 +49,7 @@ const initialState: State = {
moves: [],
ply: 0,
mobile: isMobile(),
activeTab: "load",
};
const [state, setState] = createStore(initialState);

View File

@@ -209,6 +209,7 @@ export type Handlers = {
changePiecesStyle: (style: PiecesStyle) => void;
loadPGN: (pgn: string) => Promise<void>;
loadFEN: (fen: string) => Promise<void>;
importPGN: (link: string) => Promise<void>;
downloadImage: () => Promise<void>;
downloadAnimation: () => Promise<void>;
};

View File

@@ -1,44 +1,43 @@
import { Component, createSignal, Switch, Match } from "solid-js";
import { Component, Switch, Match } from "solid-js";
import Moves from "./Moves";
import Controls from "./Controls";
import Load from "./Load";
import { Handlers } from "../../types";
import "./GameTabs.css";
import { setState, state } from "../../state";
const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
props
) => {
const [tab, setTab] = createSignal("load");
return (
<div class="game-tabs">
<div class="tabs">
<button
class={
"game-tabs__btn" +
(tab() === "moves" ? " game-tabs__btn--active" : "")
(state.activeTab === "game" ? " game-tabs__btn--active" : "")
}
onClick={() => setTab("moves")}
onClick={() => setState("activeTab", "game")}
>
GAME
</button>
<button
class={
"game-tabs__btn" +
(tab() === "load" ? " game-tabs__btn--active" : "")
(state.activeTab === "load" ? " game-tabs__btn--active" : "")
}
onClick={() => setTab("load")}
onClick={() => setState("activeTab", "load")}
>
LOAD
</button>
</div>
<Switch>
<Match when={tab() === "moves"}>
<Match when={state.activeTab === "game"}>
<Moves moves={props.moves} handlers={props.handlers} />
<Controls handlers={props.handlers} />
</Match>
<Match when={tab() === "load"}>
<Load handlers={props.handlers} showMoves={() => setTab("moves")} />
<Match when={state.activeTab === "load"}>
<Load handlers={props.handlers} />
</Match>
</Switch>
</div>

View File

@@ -41,3 +41,7 @@
margin-top: 10px;
color: #677794;
}
.load__link-input {
margin-top: 20px;
}

View File

@@ -3,11 +3,10 @@ import { Handlers } from "../../types";
import readFile from "../../utils/readFile";
import "./Load.css";
const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
props
) => {
const Load: Component<{ handlers: Handlers }> = (props) => {
const [fen, setFEN] = createSignal("");
const [pgn, setPGN] = createSignal("");
const [link, setLink] = createSignal("");
return (
<div class="load">
@@ -15,7 +14,7 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
class="load__fen-input"
type="text"
name="load-fen"
placeholder="PASTE FEN..."
placeholder="Paste FEN..."
spellcheck={false}
value={fen()}
onInput={(e) => setFEN(e.currentTarget.value)}
@@ -32,10 +31,31 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
LOAD FEN
</button>
<hr />
<input
class="load__link-input"
type="text"
name="load-link"
placeholder="Paste lichess link..."
spellcheck={false}
value={link()}
onInput={(e) => setLink(e.currentTarget.value)}
/>
<button
class="load__link-btn"
onClick={() => {
if (link()) {
props.handlers.importPGN(link());
setLink("");
}
}}
>
IMPORT GAME
</button>
<hr />
<textarea
class="load__pgn-input"
name="load-pgn"
placeholder="PASTE PGN..."
placeholder="Paste PGN..."
spellcheck={false}
value={pgn()}
onInput={(e) => setPGN(e.currentTarget.value)}
@@ -46,7 +66,6 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
if (pgn()) {
props.handlers.loadPGN(pgn());
setPGN("");
props.showMoves();
}
}}
>
@@ -62,7 +81,6 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
if (target?.files && target.files.length > 0) {
const content = await readFile(target.files[0]);
props.handlers.loadPGN(content);
props.showMoves();
}
}}
></input>