WIP
This commit is contained in:
@@ -7,6 +7,7 @@ import drawPieces from "./layers/drawPieces";
|
|||||||
import drawHeader from "./layers/drawHeader";
|
import drawHeader from "./layers/drawHeader";
|
||||||
import drawExtraInfo from "./layers/drawExtraInfo";
|
import drawExtraInfo from "./layers/drawExtraInfo";
|
||||||
import boards from "./styles-board";
|
import boards from "./styles-board";
|
||||||
|
import isLink from "../utils/isLink";
|
||||||
|
|
||||||
const defaultConfig: BoardConfig = {
|
const defaultConfig: BoardConfig = {
|
||||||
size: 720,
|
size: 720,
|
||||||
@@ -130,6 +131,7 @@ class Board {
|
|||||||
|
|
||||||
setStyle(style: BoardStyle) {
|
setStyle(style: BoardStyle) {
|
||||||
this.style = boards[style];
|
this.style = boards[style];
|
||||||
|
this.cfg.boardStyle = style;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -146,6 +148,26 @@ class Board {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flipWhite() {
|
||||||
|
if (!this.cfg.flipped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cfg.flipped = false;
|
||||||
|
this.refresh();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
flipBlack() {
|
||||||
|
if (this.cfg.flipped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cfg.flipped = true;
|
||||||
|
this.refresh();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
hideBorder() {
|
hideBorder() {
|
||||||
this.cfg.showBorder = false;
|
this.cfg.showBorder = false;
|
||||||
this.setSize(this.size);
|
this.setSize(this.size);
|
||||||
@@ -182,8 +204,14 @@ class Board {
|
|||||||
Black: "Anonymous",
|
Black: "Anonymous",
|
||||||
WhitePretty: "Anonymous",
|
WhitePretty: "Anonymous",
|
||||||
BlackPretty: "Anonymous",
|
BlackPretty: "Anonymous",
|
||||||
|
Site: isLink(this.header.Site) ? null : this.header.Site,
|
||||||
}
|
}
|
||||||
: this.header;
|
: {
|
||||||
|
...this.header,
|
||||||
|
Site: isLink(this.header.Site)
|
||||||
|
? (this.header.Site as string).replace(/^http[s]*:\/\//, "")
|
||||||
|
: this.header.Site,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async titleFrame(header: Header) {
|
async titleFrame(header: Header) {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { PieceType, PieceColor, BoardData, Position } from "../types";
|
import { PieceType, PieceColor, BoardData, Position, Header } from "../types";
|
||||||
import { Chess, ChessInstance } from "chess.js";
|
import { Chess, ChessInstance } from "chess.js";
|
||||||
import { cleanPGN } from "./PGNHelpers";
|
import { cleanPGN } from "./PGNHelpers";
|
||||||
import { formatDate, formatName } from "../utils/formatters";
|
import { formatDate, formatName } from "../utils/formatters";
|
||||||
|
import isLink from "../utils/isLink";
|
||||||
|
|
||||||
const MATERIAL_VALUE: Map<PieceType, number> = new Map([
|
const MATERIAL_VALUE: Map<PieceType, number> = new Map([
|
||||||
["q", 9],
|
["q", 9],
|
||||||
@@ -196,6 +197,17 @@ class Game {
|
|||||||
return this.game.pgn();
|
return this.game.pgn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get anonymousPGN() {
|
||||||
|
const pgn = this.game
|
||||||
|
.pgn()
|
||||||
|
.replace(/\[White .+\]/, '[White "Anonymous"]')
|
||||||
|
.replace(/\[Black .+\]/, '[Black "Anonymous"]');
|
||||||
|
|
||||||
|
return isLink(this.header.Site)
|
||||||
|
? pgn.replace(/\[Site .+\]/, '[Site "?"]')
|
||||||
|
: pgn;
|
||||||
|
}
|
||||||
|
|
||||||
getPosition(ply: number) {
|
getPosition(ply: number) {
|
||||||
const position = this.positions[ply];
|
const position = this.positions[ply];
|
||||||
|
|
||||||
|
|||||||
49
src/main.tsx
49
src/main.tsx
@@ -71,6 +71,13 @@ const main = async () => {
|
|||||||
toggleAnonymous() {
|
toggleAnonymous() {
|
||||||
setState("boardConfig", "anonymous", !state.boardConfig.anonymous);
|
setState("boardConfig", "anonymous", !state.boardConfig.anonymous);
|
||||||
board.updateConfig({ anonymous: state.boardConfig.anonymous });
|
board.updateConfig({ anonymous: state.boardConfig.anonymous });
|
||||||
|
|
||||||
|
if (state.pgn !== "") {
|
||||||
|
const pgn = state.boardConfig.anonymous
|
||||||
|
? state.game.anonymousPGN
|
||||||
|
: state.game.pgn;
|
||||||
|
window.location.hash = `v1/pgn/${compressPGN(pgn)}`;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toggleTitleScreen() {
|
toggleTitleScreen() {
|
||||||
setState("gameConfig", "titleScreen", !state.gameConfig.titleScreen);
|
setState("gameConfig", "titleScreen", !state.gameConfig.titleScreen);
|
||||||
@@ -98,7 +105,7 @@ const main = async () => {
|
|||||||
setState("boardConfig", "piecesStyle", style);
|
setState("boardConfig", "piecesStyle", style);
|
||||||
saveConfig("board");
|
saveConfig("board");
|
||||||
},
|
},
|
||||||
async loadPGN(pgn: string) {
|
async loadPGN(pgn: string, side: "w" | "b" = "w") {
|
||||||
const game = new Game().loadPGN(pgn);
|
const game = new Game().loadPGN(pgn);
|
||||||
setState({
|
setState({
|
||||||
pgn: game.pgn,
|
pgn: game.pgn,
|
||||||
@@ -111,23 +118,38 @@ const main = async () => {
|
|||||||
|
|
||||||
await player.load(game);
|
await player.load(game);
|
||||||
setState("activeTab", "game");
|
setState("activeTab", "game");
|
||||||
|
|
||||||
|
if (side === "w") {
|
||||||
|
board.flipWhite();
|
||||||
|
} else {
|
||||||
|
board.flipBlack();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState("boardConfig", "flipped", side === "b");
|
||||||
|
|
||||||
document.title = `SHORTCASTLE - ${game.getTitle({ anonymous: false })}`;
|
document.title = `SHORTCASTLE - ${game.getTitle({ anonymous: false })}`;
|
||||||
},
|
},
|
||||||
async loadFEN(fen: string) {
|
async loadFEN(fen: string, hash = true) {
|
||||||
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 });
|
||||||
window.location.hash = `v1/fen/${state.fen}`;
|
|
||||||
await player.load(game);
|
|
||||||
setState("activeTab", "game");
|
|
||||||
|
|
||||||
if (
|
await player.load(game);
|
||||||
game.getPosition(0).turn === "b" &&
|
|
||||||
state.boardConfig.flipped === false
|
if (hash) {
|
||||||
) {
|
window.location.hash = `v1/fen/${state.fen}`;
|
||||||
setState("boardConfig", "flipped", true);
|
setState("activeTab", "game");
|
||||||
board.flip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const side = game.getPosition(0).turn;
|
||||||
|
|
||||||
|
if (side === "w") {
|
||||||
|
board.flipWhite();
|
||||||
|
} else {
|
||||||
|
board.flipBlack();
|
||||||
|
}
|
||||||
|
|
||||||
|
setState("boardConfig", "flipped", side === "b");
|
||||||
|
|
||||||
document.title = `SHORTCASTLE - FEN ${fen}`;
|
document.title = `SHORTCASTLE - FEN ${fen}`;
|
||||||
},
|
},
|
||||||
async importPGN(link: string) {
|
async importPGN(link: string) {
|
||||||
@@ -137,7 +159,7 @@ const main = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.loadPGN(result.pgn);
|
await this.loadPGN(result.pgn, result.side);
|
||||||
},
|
},
|
||||||
async downloadImage() {
|
async downloadImage() {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
@@ -182,7 +204,8 @@ const main = async () => {
|
|||||||
: fen
|
: fen
|
||||||
? handlers.loadFEN(fen)
|
? handlers.loadFEN(fen)
|
||||||
: handlers.loadFEN(
|
: handlers.loadFEN(
|
||||||
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
|
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
||||||
|
false
|
||||||
));
|
));
|
||||||
|
|
||||||
/* Register events */
|
/* Register events */
|
||||||
|
|||||||
@@ -43,7 +43,11 @@ export type State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const initialState: State = {
|
const initialState: State = {
|
||||||
boardConfig: { ...initialBoardConfig, ...saved.boardConfig },
|
boardConfig: {
|
||||||
|
...initialBoardConfig,
|
||||||
|
...saved.boardConfig,
|
||||||
|
anonymous: false,
|
||||||
|
},
|
||||||
gameConfig: { ...initialGameConfig, ...saved.gameConfig },
|
gameConfig: { ...initialGameConfig, ...saved.gameConfig },
|
||||||
game: new Game(),
|
game: new Game(),
|
||||||
pgn: "",
|
pgn: "",
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.board {
|
.board {
|
||||||
border: solid 1rem var(--color-bg-block);
|
box-shadow: 0 0 2rem #00000099;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Handlers } from "../../types";
|
|||||||
import { state } from "../../state";
|
import { state } from "../../state";
|
||||||
import "./Info.css";
|
import "./Info.css";
|
||||||
import isSafeLink from "../../utils/isSafeLink";
|
import isSafeLink from "../../utils/isSafeLink";
|
||||||
|
import isLink from "../../utils/isLink";
|
||||||
|
|
||||||
const Info: Component<{ handlers: Handlers }> = () => {
|
const Info: Component<{ handlers: Handlers }> = () => {
|
||||||
return (
|
return (
|
||||||
@@ -10,17 +11,17 @@ const Info: Component<{ handlers: Handlers }> = () => {
|
|||||||
<div className="info__players">
|
<div className="info__players">
|
||||||
<p>
|
<p>
|
||||||
<button className="info__color info__color--white"></button>
|
<button className="info__color info__color--white"></button>
|
||||||
{state.game.header.WhitePretty}{" "}
|
<Show when={!state.boardConfig.anonymous} fallback="Anonymous">
|
||||||
<span className="info__rating">
|
{state.game.header.WhitePretty}{" "}
|
||||||
{state.game.header.WhiteElo ?? "????"}
|
</Show>
|
||||||
</span>
|
<span className="info__rating">{state.game.header.WhiteElo}</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button className="info__color info__color--black"></button>
|
<button className="info__color info__color--black"></button>
|
||||||
{state.game.header.BlackPretty}{" "}
|
<Show when={!state.boardConfig.anonymous} fallback="Anonymous">
|
||||||
<span className="info__rating">
|
{state.game.header.BlackPretty}{" "}
|
||||||
{state.game.header.BlackElo ?? "????"}
|
</Show>
|
||||||
</span>
|
<span className="info__rating">{state.game.header.BlackElo}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="info__event">
|
<div className="info__event">
|
||||||
@@ -35,12 +36,18 @@ const Info: Component<{ handlers: Handlers }> = () => {
|
|||||||
<Show when={state.game.header.Site}>
|
<Show when={state.game.header.Site}>
|
||||||
<p>
|
<p>
|
||||||
<Show
|
<Show
|
||||||
when={isSafeLink(state.game.header.Site)}
|
when={
|
||||||
fallback={state.game.header.Site}
|
!state.boardConfig.anonymous || !isLink(state.game.header.Site)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<a href={state.game.header.Site ?? ""}>
|
<Show
|
||||||
{state.game.header.Site?.replace(/^https:\/\//, "")}
|
when={isSafeLink(state.game.header.Site)}
|
||||||
</a>
|
fallback={state.game.header.Site}
|
||||||
|
>
|
||||||
|
<a href={state.game.header.Site ?? ""}>
|
||||||
|
{state.game.header.Site?.replace(/^https:\/\//, "")}
|
||||||
|
</a>
|
||||||
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
</p>
|
</p>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
@@ -192,7 +192,11 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
<button
|
<button
|
||||||
class="share__btn"
|
class="share__btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(state.pgn);
|
navigator.clipboard.writeText(
|
||||||
|
state.boardConfig.anonymous
|
||||||
|
? state.game.anonymousPGN
|
||||||
|
: state.pgn
|
||||||
|
);
|
||||||
blinkCopy("pgn");
|
blinkCopy("pgn");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
14
src/utils/isLink.ts
Normal file
14
src/utils/isLink.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
const isLink = (text: string | null) => {
|
||||||
|
if (text === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new URL(text);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default isLink;
|
||||||
Reference in New Issue
Block a user