Merge pull request #9 from jhalitaksoy/feature/theme-chooser
Feature/theme chooser
This commit is contained in:
commit
06428ee7d4
@ -14,6 +14,8 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@szhsin/react-menu": "^3.0.2",
|
||||||
|
"@types/": "szhsin/react-menu",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"mancala.js": "^0.0.2-beta.2",
|
"mancala.js": "^0.0.2-beta.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
|
|||||||
65
src/Home.tsx
65
src/Home.tsx
@ -18,6 +18,10 @@ import { GameMove } from "./models/GameMove";
|
|||||||
import PitAnimator from "./animation/PitAnimator";
|
import PitAnimator from "./animation/PitAnimator";
|
||||||
import BoardViewModel from "./viewmodel/BoardViewModel";
|
import BoardViewModel from "./viewmodel/BoardViewModel";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
|
import { Menu, MenuButton, MenuItem } from "@szhsin/react-menu";
|
||||||
|
import "@szhsin/react-menu/dist/index.css";
|
||||||
|
import "@szhsin/react-menu/dist/transitions/slide.css";
|
||||||
|
import { getColorByLuminance } from "./util/ColorUtil";
|
||||||
|
|
||||||
type ConnectionState = "connecting" | "error" | "connected" | "reconnecting";
|
type ConnectionState = "connecting" | "error" | "connected" | "reconnecting";
|
||||||
|
|
||||||
@ -116,6 +120,12 @@ const Home: FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
context.themeManager.onThemeChange = () => {
|
||||||
|
updateBoardViewModel(pitAnimator.getBoardViewModelFromGame(game));
|
||||||
|
};
|
||||||
|
}, [boardViewModel]);
|
||||||
|
|
||||||
const resetGameState = () => {
|
const resetGameState = () => {
|
||||||
setGame(undefined);
|
setGame(undefined);
|
||||||
setCrashMessage(undefined);
|
setCrashMessage(undefined);
|
||||||
@ -185,7 +195,11 @@ const Home: FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => {
|
|||||||
}
|
}
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
const menuTextColor = getColorByLuminance(
|
||||||
|
context.themeManager.theme.appBarBgColor,
|
||||||
|
context.themeManager.theme.primary,
|
||||||
|
context.themeManager.theme.primaryLight
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -225,7 +239,54 @@ const Home: FunctionComponent<{ initial?: number }> = ({ initial = 0 }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h1 style={{ margin: "10px 0px" }}>{context.texts.Mancala}</h1>
|
<h1 style={{ margin: "10px 0px" }}>{context.texts.Mancala}</h1>
|
||||||
<div>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginRight: "1vw",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
menuStyle={{
|
||||||
|
background: context.themeManager.theme.appBarBgColor,
|
||||||
|
}}
|
||||||
|
menuButton={
|
||||||
|
<span class="material-symbols-outlined">light_mode</span>
|
||||||
|
}
|
||||||
|
transition
|
||||||
|
align="end"
|
||||||
|
>
|
||||||
|
{context.themeManager.themes.map((theme) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
style={{
|
||||||
|
color: menuTextColor,
|
||||||
|
}}
|
||||||
|
onClick={() => (context.themeManager.theme = theme)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
borderRadius: "5vw",
|
||||||
|
background: theme.boardColor,
|
||||||
|
width: "1vw",
|
||||||
|
height: "1vw",
|
||||||
|
marginRight: "1vw",
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
{theme.name}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
{renderNewGameButton()}
|
{renderNewGameButton()}
|
||||||
{game &&
|
{game &&
|
||||||
!userKeyWhoLeave &&
|
!userKeyWhoLeave &&
|
||||||
|
|||||||
@ -162,7 +162,7 @@ export default class PitAnimator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBoardViewModelFromGame(game: MancalaGame): BoardViewModel {
|
public getBoardViewModelFromGame(game: MancalaGame): BoardViewModel {
|
||||||
const pitViewModels = this.createPitViewModelsFromGame(game);
|
const pitViewModels = this.createPitViewModelsFromGame(game);
|
||||||
return BoardViewModelFactory.create(v4(), pitViewModels);
|
return BoardViewModelFactory.create(v4(), pitViewModels);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { Texts, TrTr } from "./const/texts";
|
|||||||
import { RTMT } from "./rtmt/rtmt";
|
import { RTMT } from "./rtmt/rtmt";
|
||||||
import { RTMTWS } from "./rtmt/rtmt_websocket";
|
import { RTMTWS } from "./rtmt/rtmt_websocket";
|
||||||
import { UserKeyStore, UserKeyStoreImpl } from "./store/key_store";
|
import { UserKeyStore, UserKeyStoreImpl } from "./store/key_store";
|
||||||
import defaultTheme from "./theme/DefaultTheme";
|
|
||||||
import ThemeManager from "./theme/ThemeManager";
|
import ThemeManager from "./theme/ThemeManager";
|
||||||
|
|
||||||
export type Context = {
|
export type Context = {
|
||||||
@ -16,7 +15,7 @@ export const initContext = () => {
|
|||||||
const rtmt = new RTMTWS();
|
const rtmt = new RTMTWS();
|
||||||
const userKeyStore = new UserKeyStoreImpl();
|
const userKeyStore = new UserKeyStoreImpl();
|
||||||
const texts = TrTr;
|
const texts = TrTr;
|
||||||
const themeManager = new ThemeManager(defaultTheme);
|
const themeManager = new ThemeManager();
|
||||||
return {
|
return {
|
||||||
rtmt: rtmt,
|
rtmt: rtmt,
|
||||||
userKeyStore: userKeyStore,
|
userKeyStore: userKeyStore,
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
<script src="./App.tsx"></script>
|
<script src="./App.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html{
|
html{
|
||||||
|
|||||||
@ -11,6 +11,8 @@ const colors = {
|
|||||||
const colorSpecial = "#F6A9A9";
|
const colorSpecial = "#F6A9A9";
|
||||||
|
|
||||||
const defaultTheme: Theme = {
|
const defaultTheme: Theme = {
|
||||||
|
id: "1",
|
||||||
|
name: "Default Light Theme",
|
||||||
background: "#EEEEEE",
|
background: "#EEEEEE",
|
||||||
appBarBgColor: colors.quaternary,
|
appBarBgColor: colors.quaternary,
|
||||||
primary: colors.primary,
|
primary: colors.primary,
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { Theme } from "./Theme";
|
import { Theme } from "./Theme";
|
||||||
|
|
||||||
const oldTheme: Theme = {
|
const oldTheme: Theme = {
|
||||||
|
id: "0",
|
||||||
|
name: "Old Theme",
|
||||||
background: "#EEEEEE",
|
background: "#EEEEEE",
|
||||||
appBarBgColor: "rgb(228, 228, 228)",
|
appBarBgColor: "#e4e4e4",
|
||||||
primary: "#4D606E",
|
primary: "#4D606E",
|
||||||
primaryLight: "#EEEEEE",
|
primaryLight: "#EEEEEE",
|
||||||
playerTurnColor: "#84b8a6",
|
playerTurnColor: "#84b8a6",
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
export type Theme = {
|
export type Theme = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
primary: string;
|
primary: string;
|
||||||
primaryLight: string;
|
primaryLight: string;
|
||||||
background: string;
|
background: string;
|
||||||
|
|||||||
@ -1,18 +1,39 @@
|
|||||||
|
import defaultTheme from "./DefaultTheme";
|
||||||
|
import oldTheme from "./OldTheme";
|
||||||
import { Theme } from "./Theme";
|
import { Theme } from "./Theme";
|
||||||
|
|
||||||
|
export const themes = [defaultTheme, oldTheme];
|
||||||
|
|
||||||
|
const THEME_ID = "theme_id";
|
||||||
|
|
||||||
export default class ThemeManager {
|
export default class ThemeManager {
|
||||||
_theme: Theme;
|
_theme: Theme;
|
||||||
onThemeChange: (theme: Theme) => void;
|
onThemeChange: (theme: Theme) => void;
|
||||||
constructor(theme: Theme) {
|
constructor() {
|
||||||
this._theme = theme;
|
this._theme = this.readFromLocalStorage() || defaultTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get theme() {
|
public get theme() {
|
||||||
return this._theme;
|
return this._theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set theme(value) {
|
public set theme(value: Theme) {
|
||||||
this._theme = value;
|
this._theme = value;
|
||||||
this.onThemeChange?.(value);
|
this.onThemeChange?.(value);
|
||||||
|
this.writetToLocalStorage(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private writetToLocalStorage(value: Theme) {
|
||||||
|
localStorage.setItem(THEME_ID, value.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readFromLocalStorage(): Theme {
|
||||||
|
const themeID = localStorage.getItem(THEME_ID);
|
||||||
|
const theme = themes.find((eachTheme: Theme) => themeID === eachTheme.id);
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get themes(): Theme[] {
|
||||||
|
return themes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
yarn.lock
36
yarn.lock
@ -1011,6 +1011,21 @@
|
|||||||
"@parcel/utils" "^1.11.0"
|
"@parcel/utils" "^1.11.0"
|
||||||
physical-cpu-count "^2.0.0"
|
physical-cpu-count "^2.0.0"
|
||||||
|
|
||||||
|
"@szhsin/react-menu@^3.0.2":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@szhsin/react-menu/-/react-menu-3.0.2.tgz#d22971c53d56e6d404c9d3c98f533907cd8f03dc"
|
||||||
|
integrity sha512-m9Ly+cT+CxQx3xhq90CVaOLQWU7f7UKeMxfDt1gPYV23tDwEe8Zo6PO547qPlAEGEwwb9MdA38U8OyueXKJc2g==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
react-transition-state "^1.1.4"
|
||||||
|
|
||||||
|
"@types/@szhsin/react-menu":
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://codeload.github.com/szhsin/react-menu/tar.gz/28284b2183801fb4f6a95e9270ce580441c5da70"
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
react-transition-state "^1.1.4"
|
||||||
|
|
||||||
"@types/prop-types@*":
|
"@types/prop-types@*":
|
||||||
version "15.7.5"
|
version "15.7.5"
|
||||||
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
|
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
|
||||||
@ -3364,7 +3379,7 @@ log-symbols@^2.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
chalk "^2.0.1"
|
chalk "^2.0.1"
|
||||||
|
|
||||||
loose-envify@^1.1.0:
|
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
|
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
@ -4333,6 +4348,15 @@ process@^0.11.10:
|
|||||||
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
|
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
|
||||||
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
||||||
|
|
||||||
|
prop-types@^15.7.2:
|
||||||
|
version "15.8.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||||
|
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
react-is "^16.13.1"
|
||||||
|
|
||||||
psl@^1.1.28:
|
psl@^1.1.28:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz"
|
resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz"
|
||||||
@ -4433,6 +4457,16 @@ react-dom@^17.0.2:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
scheduler "^0.20.2"
|
scheduler "^0.20.2"
|
||||||
|
|
||||||
|
react-is@^16.13.1:
|
||||||
|
version "16.13.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
|
react-transition-state@^1.1.4:
|
||||||
|
version "1.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-transition-state/-/react-transition-state-1.1.4.tgz#113224eaa27e0ff81661305e44d5e0348cdf61ac"
|
||||||
|
integrity sha512-6nQLWWx95gYazCm6OdtD1zGbRiirvVXPrDtHAGsYb4xs9spMM7bA8Vx77KCpjL8PJ8qz1lXFGz2PTboCSvt7iw==
|
||||||
|
|
||||||
react@^17.0.2:
|
react@^17.0.2:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user