WIP
This commit is contained in:
@@ -2,16 +2,18 @@ import { Component, Show } from "solid-js";
|
||||
import type { DeepReadonly } from "solid-js/store";
|
||||
|
||||
import { Handlers } from "../types";
|
||||
import { setState, State, state } from "../state";
|
||||
import { State, state } from "../state";
|
||||
|
||||
import Header from "./components/Header";
|
||||
import GameTabs from "./components/GameTabs";
|
||||
import SetupTabs from "./components/SetupTabs";
|
||||
import Controls from "./components/Controls";
|
||||
import Popup from "./components/Popup";
|
||||
|
||||
import "./App.css";
|
||||
import saveConfig from "../persistance/saveConfig";
|
||||
import WrongBrowserPopup from "./components/popups/WrongBrowserPopup";
|
||||
import AndroidAppPopup from "./components/popups/AndroidAppPopup";
|
||||
import IOSAppPopup from "./components/popups/IOSAppPopup";
|
||||
import About from "./components/About";
|
||||
|
||||
const App: Component<{ handlers: Handlers; state: DeepReadonly<State> }> = (
|
||||
props
|
||||
@@ -44,17 +46,10 @@ const App: Component<{ handlers: Handlers; state: DeepReadonly<State> }> = (
|
||||
></GameTabs>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={state.siteConfig.wrongBrowserPopup}>
|
||||
<Popup
|
||||
handlers={props.handlers}
|
||||
onClose={() => {
|
||||
setState("siteConfig", "wrongBrowserPopup", false);
|
||||
saveConfig("site");
|
||||
}}
|
||||
>
|
||||
{state.browser} | {state.os}
|
||||
</Popup>
|
||||
</Show>
|
||||
<About />
|
||||
<WrongBrowserPopup />
|
||||
<AndroidAppPopup />
|
||||
<IOSAppPopup />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
77
src/ui/components/About.css
Normal file
77
src/ui/components/About.css
Normal file
@@ -0,0 +1,77 @@
|
||||
.about {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: grid;
|
||||
vertical-align: middle;
|
||||
padding-top: var(--header-height);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.about__box {
|
||||
background-color: var(--color-bg-input);
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
padding: 2rem;
|
||||
padding-top: 6rem;
|
||||
border-radius: 0.5rem;
|
||||
position: relative;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.about__close {
|
||||
width: 3.2rem;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
.about__title {
|
||||
text-align: left;
|
||||
margin: 0 4.2rem 3rem 0;
|
||||
}
|
||||
|
||||
.about__content {
|
||||
text-align: left;
|
||||
font-size: 1.2rem;
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.about__content p {
|
||||
margin-top: 2rem;
|
||||
font-size: 1.4rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.about__content ul {
|
||||
margin-top: 2rem;
|
||||
list-style: none;
|
||||
font-size: 1.4rem;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.about__content li {
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.about__content kbd {
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 2rem;
|
||||
background-color: var(--color-tab);
|
||||
color: var(--color-text-contrast);
|
||||
padding: 0.5rem 1rem;
|
||||
margin-right: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0.5rem 0.5rem 1rem #00000033;
|
||||
font-family: "Fira Mono", monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.about__shortcuts {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
90
src/ui/components/About.tsx
Normal file
90
src/ui/components/About.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { setState, state } from "../../state";
|
||||
|
||||
import "./About.css";
|
||||
|
||||
const About: Component = () => {
|
||||
return (
|
||||
<Show when={state.about}>
|
||||
<div className="about">
|
||||
<div className="about__box">
|
||||
<button
|
||||
className="about__close"
|
||||
onClick={() => setState("about", !state.about)}
|
||||
>
|
||||
<i class="las la-times"></i>
|
||||
</button>
|
||||
<div className="about__content">
|
||||
<h2>About</h2>
|
||||
<p>
|
||||
<b>ShareChess</b> is a free, open source website that allows you
|
||||
to share chess games as self-contained replay links (the whole
|
||||
game is stored in the url without the need for a database), PNG
|
||||
images, or GIF / MP4 / WebM animations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The website provides a high variety of chessboard and piece
|
||||
designs to serve as an open alternative for commercial chess GIF
|
||||
makers.
|
||||
</p>
|
||||
<p>
|
||||
You can find the complete source code on our{" "}
|
||||
<a href="https://github.com/sharechess/sharechess">GitHub page</a>
|
||||
.
|
||||
</p>
|
||||
<hr />
|
||||
<h2>Keyboard Shortcuts</h2>
|
||||
<div className="about__shortcuts">
|
||||
<ul>
|
||||
<li>
|
||||
<kbd>→</kbd> Next move
|
||||
</li>
|
||||
<li>
|
||||
<kbd>←</kbd> Previous move
|
||||
</li>
|
||||
<li>
|
||||
<kbd>↑</kbd> Start position
|
||||
</li>
|
||||
<li>
|
||||
<kbd>↓</kbd> Final position
|
||||
</li>
|
||||
<li>
|
||||
<kbd>f</kbd> Flip the board
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Space</kbd> Play / Pause
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Enter</kbd> Analyze on Lichess
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<kbd>l</kbd> Load from clipboard
|
||||
</li>
|
||||
<li>
|
||||
<kbd>a</kbd> Toggle anonymous
|
||||
</li>
|
||||
<li>
|
||||
<kbd>b</kbd> Toggle border
|
||||
</li>
|
||||
<li>
|
||||
<kbd>i</kbd> Toggle extra info
|
||||
</li>
|
||||
<li>
|
||||
<kbd>h</kbd> Toggle header (title screen)
|
||||
</li>
|
||||
<li>
|
||||
<kbd>s</kbd> Toggle shadows
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default About;
|
||||
@@ -1,11 +1,9 @@
|
||||
import { Component, createSignal } from "solid-js";
|
||||
import { Component } from "solid-js";
|
||||
import { Handlers } from "../../types";
|
||||
import { state } from "../../state";
|
||||
import { setState, state } from "../../state";
|
||||
import "./Header.css";
|
||||
|
||||
const Header: Component<{ handlers: Handlers }> = (props) => {
|
||||
const [darkMode, setDarkMode] = createSignal(true);
|
||||
|
||||
return (
|
||||
<header class="header-box">
|
||||
<div class="header__logo">
|
||||
@@ -14,9 +12,13 @@ const Header: Component<{ handlers: Handlers }> = (props) => {
|
||||
</a>
|
||||
</div>
|
||||
<div class="header__options">
|
||||
{/* <div class="header__options-ico" onClick={() => {}}>
|
||||
<div
|
||||
class="header__options-ico"
|
||||
onClick={() => setState("about", !state.about)}
|
||||
title="ABOUT"
|
||||
>
|
||||
<i class="las la-question-circle"></i>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="header__options-ico"
|
||||
|
||||
@@ -17,8 +17,7 @@ const Load: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||
<button
|
||||
classList={{ "load__game-btn": true, "btn--error": clipError() }}
|
||||
onClick={async () => {
|
||||
const clip = await navigator.clipboard.readText();
|
||||
const success = await props.handlers.load(clip);
|
||||
const success = await props.handlers.loadFromClipboard();
|
||||
|
||||
if (!success) {
|
||||
setClipError(true);
|
||||
|
||||
@@ -4,6 +4,7 @@ import Scrollable from "./reusable/Scrollable";
|
||||
import { state, setState } from "../../state";
|
||||
import "./Share.css";
|
||||
import download from "../../utils/download";
|
||||
import link from "../../persistance/link";
|
||||
|
||||
const Share: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||
const [copyId, setCopyId] = createSignal("");
|
||||
@@ -19,6 +20,17 @@ const Share: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||
<Scrollable class={"share" + (props.class ? ` ${props.class}` : "")}>
|
||||
<div className="share__view">
|
||||
<h2 class="header--first">Board options</h2>
|
||||
<button
|
||||
classList={{
|
||||
options__button: true,
|
||||
"options__button--last": false,
|
||||
"options__button--active": state.anonymous,
|
||||
}}
|
||||
onClick={props.handlers.toggleAnonymous}
|
||||
title="TOGGLE ANONYMOUS"
|
||||
>
|
||||
<i class="las la-user-secret"></i>
|
||||
</button>
|
||||
<button
|
||||
classList={{
|
||||
options__button: true,
|
||||
@@ -57,17 +69,6 @@ const Share: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||
>
|
||||
<i class="las la-heading"></i>
|
||||
</button>
|
||||
<button
|
||||
classList={{
|
||||
options__button: true,
|
||||
"options__button--last": false,
|
||||
"options__button--active": state.anonymous,
|
||||
}}
|
||||
onClick={props.handlers.toggleAnonymous}
|
||||
title="TOGGLE ANONYMOUS"
|
||||
>
|
||||
<i class="las la-user-secret"></i>
|
||||
</button>
|
||||
<button
|
||||
classList={{
|
||||
options__button: true,
|
||||
@@ -110,8 +111,7 @@ const Share: Component<{ handlers: Handlers; class?: string }> = (props) => {
|
||||
<button
|
||||
class="share__btn share__btn--right"
|
||||
onClick={() => {
|
||||
const link = `${location.origin}/#fen/${encodeURI(state.fen)}`;
|
||||
navigator.clipboard.writeText(link);
|
||||
navigator.clipboard.writeText(link.getFENLink(state.fen));
|
||||
blinkCopy("fen-link");
|
||||
}}
|
||||
>
|
||||
|
||||
38
src/ui/components/popups/AndroidAppPopup.tsx
Normal file
38
src/ui/components/popups/AndroidAppPopup.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { setState, state } from "../../../state";
|
||||
import Popup from "../reusable/Popup";
|
||||
import saveConfig from "../../../persistance/saveConfig";
|
||||
|
||||
const AndroidAppPopup: Component = () => {
|
||||
return (
|
||||
<Show
|
||||
when={state.siteConfig.androidAppPopup && state.os?.includes("Android")}
|
||||
>
|
||||
<Popup
|
||||
onClose={() => {
|
||||
setState("siteConfig", "androidAppPopup", false);
|
||||
saveConfig("site");
|
||||
}}
|
||||
title="Tip"
|
||||
>
|
||||
<p>
|
||||
For easy access, you can install this website as a standalone app.
|
||||
</p>
|
||||
<ul>
|
||||
To do that:
|
||||
<li>open the website in Chrome,</li>
|
||||
<li>tap the menu icon (3 dots in the corner),</li>
|
||||
<li>
|
||||
tap{" "}
|
||||
<u>
|
||||
<b>Add to Home screen</b>
|
||||
</u>
|
||||
.
|
||||
</li>
|
||||
</ul>
|
||||
</Popup>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default AndroidAppPopup;
|
||||
36
src/ui/components/popups/IOSAppPopup.tsx
Normal file
36
src/ui/components/popups/IOSAppPopup.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { setState, state } from "../../../state";
|
||||
import Popup from "../reusable/Popup";
|
||||
import saveConfig from "../../../persistance/saveConfig";
|
||||
|
||||
const IOSAppPopup: Component = () => {
|
||||
return (
|
||||
<Show when={state.siteConfig.iOSAppPopup && state.os?.includes("iOS")}>
|
||||
<Popup
|
||||
onClose={() => {
|
||||
setState("siteConfig", "iOSAppPopup", false);
|
||||
saveConfig("site");
|
||||
}}
|
||||
title="Tip"
|
||||
>
|
||||
<p>
|
||||
For easy access, you can install this website as a standalone app.
|
||||
</p>
|
||||
<ul>
|
||||
To do that:
|
||||
<li>open the website in Safari,</li>
|
||||
<li>tap the Share icon,</li>
|
||||
<li>
|
||||
tap{" "}
|
||||
<u>
|
||||
<b>Add to Home Screen</b>
|
||||
</u>
|
||||
.
|
||||
</li>
|
||||
</ul>
|
||||
</Popup>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default IOSAppPopup;
|
||||
36
src/ui/components/popups/WrongBrowserPopup.tsx
Normal file
36
src/ui/components/popups/WrongBrowserPopup.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { setState, state } from "../../../state";
|
||||
import Popup from "../reusable/Popup";
|
||||
import saveConfig from "../../../persistance/saveConfig";
|
||||
|
||||
const WrongBrowserPopup: Component = () => {
|
||||
return (
|
||||
<Show
|
||||
when={
|
||||
!state.siteConfig.iOSAppPopup &&
|
||||
state.siteConfig.wrongBrowserPopup &&
|
||||
state.os === "iOS" &&
|
||||
!state.browser?.includes("Safari")
|
||||
}
|
||||
>
|
||||
<Popup
|
||||
onClose={() => {
|
||||
setState("siteConfig", "wrongBrowserPopup", false);
|
||||
saveConfig("site");
|
||||
}}
|
||||
title="Note"
|
||||
>
|
||||
<p>Saving files may not work correctly in this browser.</p>
|
||||
<p>
|
||||
To enjoy the full functionality of the website, please open it in{" "}
|
||||
<u>
|
||||
<b>Safari</b>
|
||||
</u>
|
||||
.
|
||||
</p>
|
||||
</Popup>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
export default WrongBrowserPopup;
|
||||
@@ -3,7 +3,7 @@
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
padding: 2rem;
|
||||
display: grid;
|
||||
vertical-align: middle;
|
||||
@@ -18,6 +18,7 @@
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 2rem #00000099;
|
||||
position: relative;
|
||||
border: solid 1px var(--color-highlight);
|
||||
}
|
||||
|
||||
.popup__close {
|
||||
@@ -29,6 +30,23 @@
|
||||
|
||||
.popup__title {
|
||||
text-align: left;
|
||||
margin: 0 4.2rem 2rem 0;
|
||||
/* background-color: aqua; */
|
||||
margin: 0 4.2rem 3rem 0;
|
||||
}
|
||||
|
||||
.popup__content {
|
||||
text-align: left;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.popup__content p {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.popup__content ul {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.popup__content li {
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
import { Component } from "solid-js";
|
||||
import { Handlers } from "../../types";
|
||||
import { state, setState } from "../../state";
|
||||
|
||||
import "./Popup.css";
|
||||
|
||||
const Popup: Component<{ handlers: Handlers; onClose: () => void }> = (
|
||||
props
|
||||
) => {
|
||||
const Popup: Component<{
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
}> = (props) => {
|
||||
return (
|
||||
<div className="popup">
|
||||
<div className="popup__box">
|
||||
<button className="popup__close" onClick={props.onClose}>
|
||||
<i class="las la-times"></i>
|
||||
</button>
|
||||
<h2 className="popup__title">Popup title</h2>
|
||||
<h2 className="popup__title">{props.title}</h2>
|
||||
<div className="popup__content">{props.children}</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user