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