WIP
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ const main = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const $board = document.querySelector<HTMLImageElement>("#board");
|
const $board = document.querySelector<HTMLImageElement>("#board");
|
||||||
$board?.appendChild(board.canvas);
|
$board?.prepend(board.canvas);
|
||||||
|
|
||||||
/* Restore game from the url */
|
/* Restore game from the url */
|
||||||
|
|
||||||
@@ -219,6 +219,9 @@ const main = async () => {
|
|||||||
));
|
));
|
||||||
|
|
||||||
/* Register events */
|
/* Register events */
|
||||||
|
document.addEventListener("dblclick", function (el) {
|
||||||
|
el.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
if (!state.mobile) {
|
if (!state.mobile) {
|
||||||
const keyMapping: { [key: string]: () => void } = {
|
const keyMapping: { [key: string]: () => void } = {
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ const initialGameConfig: GameConfig = {
|
|||||||
animationSize: "M",
|
animationSize: "M",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TabName = "game" | "load" | "share" | "boards" | "pieces";
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
boardConfig: BoardConfig;
|
boardConfig: BoardConfig;
|
||||||
gameConfig: GameConfig;
|
gameConfig: GameConfig;
|
||||||
@@ -39,7 +41,8 @@ export type State = {
|
|||||||
moves: string[];
|
moves: string[];
|
||||||
ply: number;
|
ply: number;
|
||||||
mobile: boolean;
|
mobile: boolean;
|
||||||
activeTab: "game" | "load";
|
layout: "single" | "double" | "triple";
|
||||||
|
activeTab: TabName;
|
||||||
playing: boolean;
|
playing: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,6 +59,7 @@ const initialState: State = {
|
|||||||
moves: [],
|
moves: [],
|
||||||
ply: 0,
|
ply: 0,
|
||||||
mobile,
|
mobile,
|
||||||
|
layout: mobile ? "single" : "triple",
|
||||||
activeTab: "load",
|
activeTab: "load",
|
||||||
playing: false,
|
playing: false,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -188,6 +188,12 @@ a:hover {
|
|||||||
|
|
||||||
.board-box {
|
.board-box {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
padding: var(--header-height) 0 1rem 0;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board {
|
||||||
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setup-box {
|
.setup-box {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import type { Component } from "solid-js";
|
import { Component, Show } from "solid-js";
|
||||||
import type { DeepReadonly } from "solid-js/store";
|
import type { DeepReadonly } from "solid-js/store";
|
||||||
|
|
||||||
import { Handlers } from "../types";
|
import { Handlers } from "../types";
|
||||||
import { State } from "../state";
|
import { State, state } from "../state";
|
||||||
|
|
||||||
import Header from "./components/Header";
|
import Header from "./components/Header";
|
||||||
import GameTabs from "./components/GameTabs";
|
import GameTabs from "./components/GameTabs";
|
||||||
import SetupTabs from "./components/SetupTabs";
|
import SetupTabs from "./components/SetupTabs";
|
||||||
|
import Controls from "./components/Controls";
|
||||||
|
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
@@ -17,10 +18,16 @@ const App: Component<{ handlers: Handlers; state: DeepReadonly<State> }> = (
|
|||||||
<>
|
<>
|
||||||
<Header handlers={props.handlers} />
|
<Header handlers={props.handlers} />
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<div id="setup" class="setup-box">
|
<Show when={state.layout === "triple"}>
|
||||||
<SetupTabs handlers={props.handlers}></SetupTabs>
|
<div id="setup" class="setup-box">
|
||||||
|
<SetupTabs handlers={props.handlers}></SetupTabs>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<div id="board" class="board-box">
|
||||||
|
<Show when={state.layout === "single"}>
|
||||||
|
<Controls handlers={props.handlers} />
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<div id="board" class="board-box"></div>
|
|
||||||
<div id="moves" class="game-box">
|
<div id="moves" class="game-box">
|
||||||
<GameTabs
|
<GameTabs
|
||||||
moves={props.state.moves}
|
moves={props.state.moves}
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ const prepareBoards = async () => {
|
|||||||
return boards;
|
return boards;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Boards: Component<{ handlers: Handlers }> = (props) => {
|
const Boards: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||||
const [boards, setBoards] = createSignal<BoardPreview[]>([]);
|
const [boards, setBoards] = createSignal<BoardPreview[]>([]);
|
||||||
|
|
||||||
prepareBoards().then((data) => setBoards(data));
|
prepareBoards().then((data) => setBoards(data));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scrollable class="boards">
|
<Scrollable class={"boards" + (props.class ? ` ${props.class}` : "")}>
|
||||||
<For each={boards()}>
|
<For each={boards()}>
|
||||||
{(board) => {
|
{(board) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -8,39 +8,24 @@
|
|||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
@media screen and (max-width: 1024px) {
|
||||||
.game-box {
|
.game-box {
|
||||||
height: auto;
|
padding: 0;
|
||||||
|
height: 800px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tabs {
|
.game {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 38px 195px 1fr 84px;
|
grid-template-rows: 38px 195px 1fr 84px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tabs__btn {
|
.game-tabs {
|
||||||
width: 48%;
|
display: grid;
|
||||||
border-bottom-left-radius: 0;
|
grid-auto-flow: column;
|
||||||
border-bottom-right-radius: 0;
|
grid-template-columns: 1fr 1fr;
|
||||||
height: 38px;
|
column-gap: 0.5rem;
|
||||||
background: var(--color-tab);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tabs__btn:hover {
|
.span3 {
|
||||||
background: var(--color-tab-light);
|
grid-row-end: span 3;
|
||||||
}
|
|
||||||
|
|
||||||
.game-tabs__btn--active {
|
|
||||||
width: 50%;
|
|
||||||
background: var(--color-bg-block);
|
|
||||||
color: var(--color-text);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-tabs__btn--active:hover {
|
|
||||||
background: var(--color-bg-block);
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-tabs__btn:nth-child(1) {
|
|
||||||
margin-right: 2%;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,55 @@
|
|||||||
import { Component, Switch, Match } from "solid-js";
|
import { Component, Switch, Match, Show } from "solid-js";
|
||||||
import Moves from "./Moves";
|
import Moves from "./Moves";
|
||||||
import Controls from "./Controls";
|
import Controls from "./Controls";
|
||||||
import Info from "./Info";
|
import Info from "./Info";
|
||||||
import Load from "./Load";
|
import Load from "./Load";
|
||||||
|
import Share from "./Share";
|
||||||
|
import Boards from "./Boards";
|
||||||
|
import Pieces from "./Pieces";
|
||||||
|
import Tab from "./reusable/Tab";
|
||||||
import { Handlers } from "../../types";
|
import { Handlers } from "../../types";
|
||||||
|
import { setState, state, TabName } from "../../state";
|
||||||
import "./GameTabs.css";
|
import "./GameTabs.css";
|
||||||
import { setState, state } from "../../state";
|
|
||||||
|
const setTab = (tab: TabName) => {
|
||||||
|
setState("activeTab", tab);
|
||||||
|
};
|
||||||
|
|
||||||
const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
||||||
props
|
props
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<div class="game-tabs">
|
<div class="game">
|
||||||
<div class="tabs">
|
<div class="game-tabs">
|
||||||
<button
|
<Tab name="game" setTab={setTab} isActive={state.activeTab === "game"}>
|
||||||
class={
|
|
||||||
"game-tabs__btn" +
|
|
||||||
(state.activeTab === "game" ? " game-tabs__btn--active" : "")
|
|
||||||
}
|
|
||||||
onClick={() => setState("activeTab", "game")}
|
|
||||||
>
|
|
||||||
GAME
|
GAME
|
||||||
</button>
|
</Tab>
|
||||||
<button
|
<Tab name="load" setTab={setTab} isActive={state.activeTab === "load"}>
|
||||||
class={
|
|
||||||
"game-tabs__btn" +
|
|
||||||
(state.activeTab === "load" ? " game-tabs__btn--active" : "")
|
|
||||||
}
|
|
||||||
onClick={() => setState("activeTab", "load")}
|
|
||||||
>
|
|
||||||
LOAD
|
LOAD
|
||||||
</button>
|
</Tab>
|
||||||
|
<Show when={state.layout !== "triple"}>
|
||||||
|
<Tab
|
||||||
|
name="share"
|
||||||
|
setTab={setTab}
|
||||||
|
isActive={state.activeTab === "share"}
|
||||||
|
>
|
||||||
|
<i class="las la-share"></i>
|
||||||
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
name="boards"
|
||||||
|
setTab={setTab}
|
||||||
|
isActive={state.activeTab === "boards"}
|
||||||
|
>
|
||||||
|
<i class="las la-chess-board"></i>
|
||||||
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
name="pieces"
|
||||||
|
setTab={setTab}
|
||||||
|
isActive={state.activeTab === "pieces"}
|
||||||
|
>
|
||||||
|
<i class="las la-chess"></i>
|
||||||
|
</Tab>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={state.activeTab === "game"}>
|
<Match when={state.activeTab === "game"}>
|
||||||
@@ -39,8 +58,19 @@ const GameTabs: Component<{ moves: readonly string[]; handlers: Handlers }> = (
|
|||||||
<Controls handlers={props.handlers} />
|
<Controls handlers={props.handlers} />
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={state.activeTab === "load"}>
|
<Match when={state.activeTab === "load"}>
|
||||||
<Load handlers={props.handlers} />
|
<Load handlers={props.handlers} class="span3" />
|
||||||
</Match>
|
</Match>
|
||||||
|
<Show when={state.layout !== "triple"}>
|
||||||
|
<Match when={state.activeTab === "share"}>
|
||||||
|
<Share handlers={props.handlers} class="span3" />
|
||||||
|
</Match>
|
||||||
|
<Match when={state.activeTab === "boards"}>
|
||||||
|
<Boards handlers={props.handlers} class="span3" />
|
||||||
|
</Match>
|
||||||
|
<Match when={state.activeTab === "pieces"}>
|
||||||
|
<Pieces handlers={props.handlers} class="span3" />
|
||||||
|
</Match>
|
||||||
|
</Show>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-bottom-left-radius: 5px;
|
border-bottom-left-radius: 5px;
|
||||||
border-bottom-right-radius: 5px;
|
border-bottom-right-radius: 5px;
|
||||||
grid-row-end: span 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.load__pgn-input {
|
.load__pgn-input {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import readFile from "../../utils/readFile";
|
|||||||
import { state } from "../../state";
|
import { state } from "../../state";
|
||||||
import "./Load.css";
|
import "./Load.css";
|
||||||
|
|
||||||
const Load: Component<{ handlers: Handlers }> = (props) => {
|
const Load: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||||
const [fen, setFEN] = createSignal("");
|
const [fen, setFEN] = createSignal("");
|
||||||
const [pgn, setPGN] = createSignal("");
|
const [pgn, setPGN] = createSignal("");
|
||||||
const [link, setLink] = createSignal("");
|
const [link, setLink] = createSignal("");
|
||||||
@@ -12,7 +12,7 @@ const Load: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
let filePicker: HTMLInputElement | undefined = undefined;
|
let filePicker: HTMLInputElement | undefined = undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="load">
|
<div class={"load" + (props.class ? ` ${props.class}` : "")}>
|
||||||
<input
|
<input
|
||||||
class="load__fen-input"
|
class="load__fen-input"
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ const pieces = Object.entries(piecesSets).map(([key, data]) => ({
|
|||||||
img: data.nw,
|
img: data.nw,
|
||||||
})) as { key: PiecesStyle; img: string }[];
|
})) as { key: PiecesStyle; img: string }[];
|
||||||
|
|
||||||
const Pieces: Component<{ handlers: Handlers }> = (props) => {
|
const Pieces: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Scrollable class="pieces">
|
<Scrollable class={"pieces" + (props.class ? ` ${props.class}` : "")}>
|
||||||
{
|
{
|
||||||
<For each={pieces}>
|
<For each={pieces}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
|
|||||||
@@ -6,12 +6,6 @@
|
|||||||
min-width: 375px;
|
min-width: 375px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
|
||||||
.setup-box {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup {
|
.setup {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -19,29 +13,9 @@
|
|||||||
grid-template-rows: 38px 1fr;
|
grid-template-rows: 38px 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setup-tabs__btn {
|
.setup-tabs {
|
||||||
width: 32%;
|
display: grid;
|
||||||
border-bottom-left-radius: 0;
|
grid-auto-flow: column;
|
||||||
border-bottom-right-radius: 0;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
height: 38px;
|
column-gap: 0.5rem;
|
||||||
background: var(--color-tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-tabs__btn:hover {
|
|
||||||
background: var(--color-tab-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-tabs__btn--active {
|
|
||||||
background: var(--color-bg-block);
|
|
||||||
color: var(--color-text);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-tabs__btn--active:hover {
|
|
||||||
background: var(--color-bg-block);
|
|
||||||
}
|
|
||||||
|
|
||||||
.setup-tabs__btn:nth-child(1),
|
|
||||||
.setup-tabs__btn:nth-child(2) {
|
|
||||||
margin-right: 2%;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import "./SetupTabs.css";
|
|||||||
import Share from "./Share";
|
import Share from "./Share";
|
||||||
import Boards from "./Boards";
|
import Boards from "./Boards";
|
||||||
import Pieces from "./Pieces";
|
import Pieces from "./Pieces";
|
||||||
|
import Tab from "./reusable/Tab";
|
||||||
|
|
||||||
const SetupTabs: Component<{
|
const SetupTabs: Component<{
|
||||||
handlers: Handlers;
|
handlers: Handlers;
|
||||||
@@ -12,34 +13,16 @@ const SetupTabs: Component<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="setup">
|
<div class="setup">
|
||||||
<div class="tabs">
|
<div class="setup-tabs">
|
||||||
<button
|
<Tab name="share" setTab={setTab} isActive={tab() === "share"}>
|
||||||
class={
|
|
||||||
"setup-tabs__btn" +
|
|
||||||
(tab() === "share" ? " setup-tabs__btn--active" : "")
|
|
||||||
}
|
|
||||||
onClick={() => setTab("share")}
|
|
||||||
>
|
|
||||||
<i class="las la-share"></i> SHARE
|
<i class="las la-share"></i> SHARE
|
||||||
</button>
|
</Tab>
|
||||||
<button
|
<Tab name="boards" setTab={setTab} isActive={tab() === "boards"}>
|
||||||
class={
|
|
||||||
"setup-tabs__btn" +
|
|
||||||
(tab() === "boards" ? " setup-tabs__btn--active" : "")
|
|
||||||
}
|
|
||||||
onClick={() => setTab("boards")}
|
|
||||||
>
|
|
||||||
<i class="las la-chess-board"></i> BOARDS
|
<i class="las la-chess-board"></i> BOARDS
|
||||||
</button>
|
</Tab>
|
||||||
<button
|
<Tab name="pieces" setTab={setTab} isActive={tab() === "pieces"}>
|
||||||
class={
|
|
||||||
"setup-tabs__btn" +
|
|
||||||
(tab() === "pieces" ? " setup-tabs__btn--active" : "")
|
|
||||||
}
|
|
||||||
onClick={() => setTab("pieces")}
|
|
||||||
>
|
|
||||||
<i class="las la-chess"></i> PIECES
|
<i class="las la-chess"></i> PIECES
|
||||||
</button>
|
</Tab>
|
||||||
</div>
|
</div>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={tab() === "share"}>
|
<Match when={tab() === "share"}>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { state, setState } from "../../state";
|
|||||||
import "./Share.css";
|
import "./Share.css";
|
||||||
import download from "../../utils/download";
|
import download from "../../utils/download";
|
||||||
|
|
||||||
const Share: Component<{ handlers: Handlers }> = (props) => {
|
const Share: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||||
const [copyId, setCopyId] = createSignal("");
|
const [copyId, setCopyId] = createSignal("");
|
||||||
const [imageRendering, setImageRendering] = createSignal(false);
|
const [imageRendering, setImageRendering] = createSignal(false);
|
||||||
const [animationRendering, setAnimationRendering] = createSignal(false);
|
const [animationRendering, setAnimationRendering] = createSignal(false);
|
||||||
@@ -16,7 +16,7 @@ const Share: Component<{ handlers: Handlers }> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scrollable class="share">
|
<Scrollable class={"share" + (props.class ? ` ${props.class}` : "")}>
|
||||||
<div className="share__view">
|
<div className="share__view">
|
||||||
<h2 class="header--first">Board options</h2>
|
<h2 class="header--first">Board options</h2>
|
||||||
<button
|
<button
|
||||||
|
|||||||
21
src/ui/components/reusable/Tab.css
Normal file
21
src/ui/components/reusable/Tab.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.tab {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
height: 38px;
|
||||||
|
background: var(--color-tab);
|
||||||
|
min-width: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab:hover {
|
||||||
|
background: var(--color-tab-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab--active {
|
||||||
|
background: var(--color-bg-block);
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab--active:hover {
|
||||||
|
background: var(--color-bg-block);
|
||||||
|
}
|
||||||
20
src/ui/components/reusable/Tab.tsx
Normal file
20
src/ui/components/reusable/Tab.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Component } from "solid-js";
|
||||||
|
import "./Tab.css";
|
||||||
|
import { TabName } from "../../../state";
|
||||||
|
|
||||||
|
const Tab: Component<{
|
||||||
|
name: TabName;
|
||||||
|
setTab: (name: TabName) => void;
|
||||||
|
isActive: boolean;
|
||||||
|
}> = (props) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
class={"tab" + (props.isActive ? " tab--active" : "")}
|
||||||
|
onClick={() => props.setTab(props.name)}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tab;
|
||||||
Reference in New Issue
Block a user