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 download from "./utils/download";
|
||||||
import { compressPGN } from "./game/PGNHelpers";
|
import { compressPGN } from "./game/PGNHelpers";
|
||||||
import extractUrlData from "./persistance/extractUrlData";
|
import extractUrlData from "./persistance/extractUrlData";
|
||||||
|
import importFromLink from "./imports/importFromLink";
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
const board = new Board(state.boardConfig);
|
const board = new Board(state.boardConfig);
|
||||||
@@ -101,12 +102,22 @@ const main = async () => {
|
|||||||
window.location.hash = `v1/pgn/${compressPGN(game.pgn)}`;
|
window.location.hash = `v1/pgn/${compressPGN(game.pgn)}`;
|
||||||
|
|
||||||
await player.load(game);
|
await player.load(game);
|
||||||
|
setState("activeTab", "game");
|
||||||
},
|
},
|
||||||
async loadFEN(fen: string) {
|
async loadFEN(fen: string) {
|
||||||
const game = new Game().loadFEN(fen);
|
const game = new Game().loadFEN(fen);
|
||||||
setState({ pgn: "", fen, moves: game.getMoves(), ply: 0, game });
|
setState({ pgn: "", fen, moves: game.getMoves(), ply: 0, game });
|
||||||
await player.load(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() {
|
async downloadImage() {
|
||||||
const data = await createImage(
|
const data = await createImage(
|
||||||
state.fen,
|
state.fen,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export type State = {
|
|||||||
moves: string[];
|
moves: string[];
|
||||||
ply: number;
|
ply: number;
|
||||||
mobile: boolean;
|
mobile: boolean;
|
||||||
|
activeTab: "game" | "load";
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: State = {
|
const initialState: State = {
|
||||||
@@ -48,6 +49,7 @@ const initialState: State = {
|
|||||||
moves: [],
|
moves: [],
|
||||||
ply: 0,
|
ply: 0,
|
||||||
mobile: isMobile(),
|
mobile: isMobile(),
|
||||||
|
activeTab: "load",
|
||||||
};
|
};
|
||||||
|
|
||||||
const [state, setState] = createStore(initialState);
|
const [state, setState] = createStore(initialState);
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ 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>;
|
||||||
|
importPGN: (link: string) => Promise<void>;
|
||||||
downloadImage: () => Promise<void>;
|
downloadImage: () => Promise<void>;
|
||||||
downloadAnimation: () => 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 Moves from "./Moves";
|
||||||
import Controls from "./Controls";
|
import Controls from "./Controls";
|
||||||
import Load from "./Load";
|
import Load from "./Load";
|
||||||
import { Handlers } from "../../types";
|
import { Handlers } from "../../types";
|
||||||
import "./GameTabs.css";
|
import "./GameTabs.css";
|
||||||
|
import { setState, state } from "../../state";
|
||||||
|
|
||||||
const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
||||||
props
|
props
|
||||||
) => {
|
) => {
|
||||||
const [tab, setTab] = createSignal("load");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="game-tabs">
|
<div class="game-tabs">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<button
|
<button
|
||||||
class={
|
class={
|
||||||
"game-tabs__btn" +
|
"game-tabs__btn" +
|
||||||
(tab() === "moves" ? " game-tabs__btn--active" : "")
|
(state.activeTab === "game" ? " game-tabs__btn--active" : "")
|
||||||
}
|
}
|
||||||
onClick={() => setTab("moves")}
|
onClick={() => setState("activeTab", "game")}
|
||||||
>
|
>
|
||||||
GAME
|
GAME
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class={
|
class={
|
||||||
"game-tabs__btn" +
|
"game-tabs__btn" +
|
||||||
(tab() === "load" ? " game-tabs__btn--active" : "")
|
(state.activeTab === "load" ? " game-tabs__btn--active" : "")
|
||||||
}
|
}
|
||||||
onClick={() => setTab("load")}
|
onClick={() => setState("activeTab", "load")}
|
||||||
>
|
>
|
||||||
LOAD
|
LOAD
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={tab() === "moves"}>
|
<Match when={state.activeTab === "game"}>
|
||||||
<Moves moves={props.moves} handlers={props.handlers} />
|
<Moves moves={props.moves} handlers={props.handlers} />
|
||||||
<Controls handlers={props.handlers} />
|
<Controls handlers={props.handlers} />
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={tab() === "load"}>
|
<Match when={state.activeTab === "load"}>
|
||||||
<Load handlers={props.handlers} showMoves={() => setTab("moves")} />
|
<Load handlers={props.handlers} />
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,3 +41,7 @@
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
color: #677794;
|
color: #677794;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load__link-input {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ import { Handlers } from "../../types";
|
|||||||
import readFile from "../../utils/readFile";
|
import readFile from "../../utils/readFile";
|
||||||
import "./Load.css";
|
import "./Load.css";
|
||||||
|
|
||||||
const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
|
const Load: Component<{ handlers: Handlers }> = (props) => {
|
||||||
props
|
|
||||||
) => {
|
|
||||||
const [fen, setFEN] = createSignal("");
|
const [fen, setFEN] = createSignal("");
|
||||||
const [pgn, setPGN] = createSignal("");
|
const [pgn, setPGN] = createSignal("");
|
||||||
|
const [link, setLink] = createSignal("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="load">
|
<div class="load">
|
||||||
@@ -15,7 +14,7 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
|
|||||||
class="load__fen-input"
|
class="load__fen-input"
|
||||||
type="text"
|
type="text"
|
||||||
name="load-fen"
|
name="load-fen"
|
||||||
placeholder="PASTE FEN..."
|
placeholder="Paste FEN..."
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
value={fen()}
|
value={fen()}
|
||||||
onInput={(e) => setFEN(e.currentTarget.value)}
|
onInput={(e) => setFEN(e.currentTarget.value)}
|
||||||
@@ -32,10 +31,31 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
|
|||||||
LOAD FEN
|
LOAD FEN
|
||||||
</button>
|
</button>
|
||||||
<hr />
|
<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
|
<textarea
|
||||||
class="load__pgn-input"
|
class="load__pgn-input"
|
||||||
name="load-pgn"
|
name="load-pgn"
|
||||||
placeholder="PASTE PGN..."
|
placeholder="Paste PGN..."
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
value={pgn()}
|
value={pgn()}
|
||||||
onInput={(e) => setPGN(e.currentTarget.value)}
|
onInput={(e) => setPGN(e.currentTarget.value)}
|
||||||
@@ -46,7 +66,6 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
|
|||||||
if (pgn()) {
|
if (pgn()) {
|
||||||
props.handlers.loadPGN(pgn());
|
props.handlers.loadPGN(pgn());
|
||||||
setPGN("");
|
setPGN("");
|
||||||
props.showMoves();
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -62,7 +81,6 @@ const Load: Component<{ handlers: Handlers; showMoves: () => void }> = (
|
|||||||
if (target?.files && target.files.length > 0) {
|
if (target?.files && target.files.length > 0) {
|
||||||
const content = await readFile(target.files[0]);
|
const content = await readFile(target.files[0]);
|
||||||
props.handlers.loadPGN(content);
|
props.handlers.loadPGN(content);
|
||||||
props.showMoves();
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
></input>
|
></input>
|
||||||
|
|||||||
Reference in New Issue
Block a user