WIP
This commit is contained in:
38
src/imports/importFromLink.ts
Normal file
38
src/imports/importFromLink.ts
Normal 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;
|
||||
11
src/main.tsx
11
src/main.tsx
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -41,3 +41,7 @@
|
||||
margin-top: 10px;
|
||||
color: #677794;
|
||||
}
|
||||
|
||||
.load__link-input {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user