From fce651a618ca6d0d64fbcea757c3e0f582e1b437 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 22 Apr 2021 12:35:53 +0200 Subject: beginnings of theme settings --- api/api.ts | 2 +- api/user/preferences.py | 4 +-- components/preferencesContext.tsx | 22 +++++++------- components/themes.tsx | 61 +++++++++++++++++++++++++++++++++++++++ components/ui.tsx | 20 ++----------- pages/_app.tsx | 1 + pages/settings.tsx | 12 ++++---- public/themes/themes.json | 34 ++++++++++++++++++++++ styles/notifications.css | 3 +- styles/themepicker.css | 50 ++++++++++++++++++++++++++++++++ 10 files changed, 170 insertions(+), 39 deletions(-) create mode 100644 components/themes.tsx create mode 100644 public/themes/themes.json create mode 100644 styles/themepicker.css diff --git a/api/api.ts b/api/api.ts index 95c63ba..d0dee96 100644 --- a/api/api.ts +++ b/api/api.ts @@ -24,13 +24,13 @@ export type ruleset = { export type userColors = { diskA: string; diskB: string; - background: string; }; export interface userPreferences { darkMode?: boolean; ruleset?: ruleset; userColors?: userColors; + theme?: string; } export interface userGameTotals { diff --git a/api/user/preferences.py b/api/user/preferences.py index 8779eaf..d903fd8 100644 --- a/api/user/preferences.py +++ b/api/user/preferences.py @@ -15,8 +15,8 @@ def format_preferences(prefs): "userColors": { "diskA": prefs.get("userColors", {}).get("diskA") or "", "diskB": prefs.get("userColors", {}).get("diskB") or "", - "background": prefs.get("userColors", {}).get("background") or "" - } + }, + "theme": prefs.get("theme") or "default", } diff --git a/components/preferencesContext.tsx b/components/preferencesContext.tsx index a169be6..965b185 100644 --- a/components/preferencesContext.tsx +++ b/components/preferencesContext.tsx @@ -20,6 +20,8 @@ export function PreferencesContextWrapper(props: { children?: ReactNode; }) { var [preferences, setPreferences] = useState(); + var [dummy, setDummy] = useState(false); //FIXME: janky fix to cause rerender + useEffect(() => { (async () => { if (!loggedIn) return; @@ -31,31 +33,29 @@ export function PreferencesContextWrapper(props: { children?: ReactNode; }) { applyPreferences(local_prefs_json); } - if (!preferences) { - var preferencesReq = await axios.request<{ preferences: userPreferences; }>({ - method: 'get', - url: `/api/user/preferences`, - headers: { 'content-type': 'application/json' }, - }); + var preferencesReq = await axios.request<{ preferences: userPreferences; }>({ + method: 'get', + url: `/api/user/preferences`, + headers: { 'content-type': 'application/json' }, + }); - window.localStorage.setItem('preferences', JSON.stringify(preferencesReq.data.preferences)); - setPreferences(preferencesReq.data.preferences); - } + window.localStorage.setItem('preferences', JSON.stringify(preferencesReq.data.preferences)); + setPreferences(preferencesReq.data.preferences); })(); }, []); - useEffect(() => applyPreferences(preferences), [preferences]); + applyPreferences(preferences); function updatePreference(newPreference: userPreferences) { var prefs: userPreferences = Object.assign(preferences, newPreference); setPreferences(prefs); - applyPreferences(prefs); axios.request({ method: 'post', url: `/api/user/preferences`, headers: { 'content-type': 'application/json' }, data: { 'newPreferences': prefs }, }); + setDummy(!dummy); } return diff --git a/components/themes.tsx b/components/themes.tsx new file mode 100644 index 0000000..be98685 --- /dev/null +++ b/components/themes.tsx @@ -0,0 +1,61 @@ +import { useEffect, useState, CSSProperties } from 'react'; +import axios from 'axios'; + +import { userPreferences } from '../api/api'; +import { Button } from './ui'; + +type previewThemeColors = { + bg: string; + fg: string; + a: string; + b: string; +} + +export type themeInfo = { + name: string; + url: string; + dark: previewThemeColors; + light: previewThemeColors; +} + +export type themeJSON = themeInfo[]; + +export default function ThemePicker(props: { preferences?: userPreferences }) { + var [ themes, setThemes ] = useState([]); + + useEffect(() => { + axios.request({ + method: 'get', + url: '/themes/themes.json', + }).then(response => { + setThemes(response.data); + }).catch(err => { + console.error(err) + }) + }, []); + + return <> + {themes.map(theme => )} + ; +} + +export function ThemeCard(props: { theme: themeInfo; dark?: boolean }) { + var mode = props.dark ? "dark" : "light"; + + return
+ +
+} diff --git a/components/ui.tsx b/components/ui.tsx index 1e9997a..c92ebfe 100644 --- a/components/ui.tsx +++ b/components/ui.tsx @@ -122,26 +122,12 @@ export function CheckBox(props: { id?: string; onclick?: (state: boolean) => void; }) { - var [gotDefaultState, setGotDefaultState] = useState(false); - var [on, setOn] = useState(props.state); - - useEffect(() => { - if (gotDefaultState) return; - setOn(props.state); - if (typeof props.state !== 'undefined') setGotDefaultState(true); - }); - - var toggle = () => { - setOn(!on); - props.onclick && props.onclick(!on); - }; - return
props.onclick && props.onclick(!props.state)} id={props.id} - className={'checkbox dispinbl ' + (on ? 'on' : 'off')} + className={'checkbox dispinbl ' + (props.state ? 'on' : 'off')} > - {on + {props.state ? : }
; diff --git a/pages/_app.tsx b/pages/_app.tsx index f53a6ff..6cbd476 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -12,6 +12,7 @@ import '../styles/recentGames.css'; import '../styles/toast.css'; import '../styles/ui.css'; import '../styles/utility.css'; +import '../styles/themepicker.css'; import '../styles/game.css'; import '../styles/gameSettings.css'; diff --git a/pages/settings.tsx b/pages/settings.tsx index 0ca2c30..d2b23eb 100644 --- a/pages/settings.tsx +++ b/pages/settings.tsx @@ -1,6 +1,6 @@ import axios from 'axios'; import reduce from 'image-blob-reduce'; -import { useContext } from 'react'; +import { useContext, useEffect } from 'react'; import { AccountAvatar } from '../components/account'; import { Footer } from '../components/footer'; @@ -9,6 +9,7 @@ import { NavBar } from '../components/navbar'; import { CenteredPage, PageTitle } from '../components/page'; import PreferencesContext from '../components/preferencesContext'; import { CheckBox, ColorPicker, IconLabelButton, Vierkant } from '../components/ui'; +import ThemePicker from '../components/themes'; import EditOutlinedIcon from '@material-ui/icons/EditOutlined'; import ExitToAppOutlinedIcon from '@material-ui/icons/ExitToAppOutlined'; @@ -101,12 +102,6 @@ export default function SettingsPage() {

Schijfjes

-
- -
-

Achtergrond

-
-

Donkere modus

+
+ +

Standaard spelregels

diff --git a/public/themes/themes.json b/public/themes/themes.json new file mode 100644 index 0000000..0b5eb08 --- /dev/null +++ b/public/themes/themes.json @@ -0,0 +1,34 @@ +[ + { + "name": "default", + "url": "default.css", + "dark": { + "bg": "#141619", + "fg": "#FFFFF3", + "a": "#FF4365", + "b": "#00D9C0" + }, + "light": { + "bg": "#E3E6EE", + "fg": "#141619", + "a": "#A63A4D", + "b": "#3AA699" + } + }, + { + "name": "classic", + "url": "classic.css", + "dark": { + "bg": "#222d33", + "fg": "#fcfffd", + "a": "#E16D82", + "b": "#71D9CC" + }, + "light": { + "bg": "#5d737e", + "fg": "#fcfffd", + "a": "#E16D82", + "b": "#71D9CC" + } + } +] diff --git a/styles/notifications.css b/styles/notifications.css index 02170ae..3ab92e7 100644 --- a/styles/notifications.css +++ b/styles/notifications.css @@ -15,8 +15,9 @@ a.notificationsArea .tuitje { left: var(--spacing-medium); bottom: 86px; transform: translate(-100%, 100%) rotate(90deg); - fill: var(--gray-700); + fill: var(--gray-800); } +html.dark a.notificationsArea .tuitje { fill: var(--gray-700); } .notificationsArea .title { margin-bottom: var(--spacing-large); diff --git a/styles/themepicker.css b/styles/themepicker.css new file mode 100644 index 0000000..4bac49d --- /dev/null +++ b/styles/themepicker.css @@ -0,0 +1,50 @@ +.themeCardWrapper { + margin: var(--spacing-medium); +} + +.themeCard { + background-color: var(--bg); + border-width: 2px; + border-style: solid; + border-color: var(--fg); + text-align: left; + + transition-duration: .1s; + transition-property: transform, box-shadow; + + height: 20px; + width: 170px; +} + +.themeCard:active { + box-shadow: 0; + transform: translateY(2px); +} + +.themeCard .name { + color: var(--fg); + margin-left: var(--spacing-small); +} + +.themeCard .disks { + background-color: var(--fg); + width: 64px; + +} + +.themeCard .disks .disk { + border-radius: 9999999px; + width: 24px; + + top: 4px; + bottom: 4px; +} + +.themeCard .disks .disk.a { + background-color: var(--a); + right: 4px; +} +.themeCard .disks .disk.b { + background-color: var(--b); + left: 6px; +} -- cgit v1.2.3