From 0edd0afb2af64d4638608a728f262fc8e3e9fc17 Mon Sep 17 00:00:00 2001 From: guusvanmeerveld Date: Fri, 25 Mar 2022 12:42:10 +0100 Subject: [PATCH] Started on settings page --- package.json | 3 +- src/interfaces/settings.ts | 7 +++ src/pages/_app.tsx | 15 ++++- src/pages/settings.tsx | 122 +++++++++++++++++++++++++++++++++++++ src/theme.ts | 9 +-- src/utils/hooks.ts | 24 ++++++++ src/utils/index.ts | 7 +++ yarn.lock | 5 ++ 8 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 src/interfaces/settings.ts create mode 100644 src/pages/settings.tsx create mode 100644 src/utils/hooks.ts diff --git a/package.json b/package.json index 01a99a1..afd9db0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-intersection-observer": "^8.33.1", - "react-query": "^3.34.16" + "react-query": "^3.34.16", + "use-local-storage-state": "^16.0.1" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^3.2.0", diff --git a/src/interfaces/settings.ts b/src/interfaces/settings.ts new file mode 100644 index 0000000..6ef85de --- /dev/null +++ b/src/interfaces/settings.ts @@ -0,0 +1,7 @@ +interface Settings { + theme?: "light" | "dark"; + primaryColor: string; + accentColor: string; +} + +export default Settings; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 6dd7295..4267fcb 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -13,6 +13,8 @@ import useMediaQuery from "@mui/material/useMediaQuery"; import SEO from "@src/next-seo.config"; import createTheme from "@src/theme"; +import { useSettings } from "@utils/hooks"; + const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, retry: 5, retryDelay: 5000 } @@ -20,9 +22,20 @@ const queryClient = new QueryClient({ }); const App = ({ Component, pageProps }: AppProps) => { + const [settings] = useSettings(); + const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)"); - const theme = useMemo(() => createTheme(prefersDarkMode), [prefersDarkMode]); + let dark: boolean; + + if (settings.theme) { + if (settings.theme == "dark") dark = true; + else dark = false; + } else { + dark = prefersDarkMode; + } + + const theme = useMemo(() => createTheme(settings, dark), [settings, dark]); return ( diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx new file mode 100644 index 0000000..52e7078 --- /dev/null +++ b/src/pages/settings.tsx @@ -0,0 +1,122 @@ +import { NextPage } from "next"; + +import { FC } from "react"; + +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import ButtonGroup from "@mui/material/ButtonGroup"; +import Container from "@mui/material/Container"; +import Divider from "@mui/material/Divider"; +import Typography from "@mui/material/Typography"; +import { + blue, + red, + green, + cyan, + purple, + yellow, + orange +} from "@mui/material/colors/"; +import { useTheme } from "@mui/material/styles/"; + +import { toCamelCase } from "@src/utils"; + +import { useSettings } from "@utils/hooks"; + +import Layout from "@components/Layout"; + +const Settings: NextPage = () => { + const [settings, setSettings] = useSettings(); + + const theme = useTheme(); + + const setSetting = (key: string, value?: string): void => { + setSettings({ ...settings, [key]: value }); + }; + + const ColorSetting: FC<{ type: string }> = ({ type }) => { + const camelCase = toCamelCase(type) as "primaryColor" | "accentColor"; + + return ( + + + {type} + + {[ + blue[800], + red[800], + green[800], + cyan[800], + purple[800], + yellow[800], + orange[800] + ].map((color) => ( + setSetting(camelCase, color)} + key={color} + component="span" + sx={{ + width: 24, + height: 24, + backgroundColor: color, + borderRadius: "50%", + border: + color == settings[camelCase] + ? { + borderColor: theme.palette.text.primary, + borderWidth: 1, + borderStyle: "solid" + } + : null, + cursor: "pointer", + ml: 1.5 + }} + /> + ))} + + ); + }; + + return ( + + + + Settings + + + + + Theme + + + + General theme + + + + + + + + + + + + + + + Player + + + + Miscellaneous + + + ); +}; + +export default Settings; diff --git a/src/theme.ts b/src/theme.ts index ac29ee9..d0534ad 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -1,15 +1,16 @@ -import { red } from "@mui/material/colors"; import { createTheme as createMUITheme } from "@mui/material/styles"; -const createTheme = (prefersDarkMode: boolean) => { +import Settings from "@interfaces/settings"; + +const createTheme = (settings: Settings, prefersDarkMode: boolean) => { return createMUITheme({ palette: { mode: prefersDarkMode ? "dark" : "light", primary: { - main: red[800] + main: settings.primaryColor }, secondary: { - main: red[800] + main: settings.accentColor } } }); diff --git a/src/utils/hooks.ts b/src/utils/hooks.ts new file mode 100644 index 0000000..b5dba8b --- /dev/null +++ b/src/utils/hooks.ts @@ -0,0 +1,24 @@ +import useLocalStorageState from "use-local-storage-state"; + +import { Dispatch, SetStateAction } from "react"; + +import { red } from "@mui/material/colors"; + +import Settings from "@interfaces/settings"; + +const defaultSettings: Settings = { + primaryColor: red[800], + accentColor: red[800] +}; + +export const useSettings = (): [ + settings: Settings, + setSetting: Dispatch> +] => { + const [settings, setSettings] = useLocalStorageState("settings", { + defaultValue: defaultSettings, + ssr: false + }); + + return [settings, setSettings]; +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index f8a7989..768376d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -12,3 +12,10 @@ export const abbreviateNumber = (value: number): string => { return `${value}${suffixes[suffixNum]}`; }; + +export const toCamelCase = (string: string): string => + string + .replace(/(?:^\w|[A-Z]|\b\w)/g, (leftTrim: string, index: number) => + index === 0 ? leftTrim.toLowerCase() : leftTrim.toUpperCase() + ) + .replace(/\s+/g, ""); diff --git a/yarn.lock b/yarn.lock index cb0b5d2..8df7b81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2663,6 +2663,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-local-storage-state@^16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/use-local-storage-state/-/use-local-storage-state-16.0.1.tgz#464bc038fe6b08146c789735a27d54199703b00c" + integrity sha512-X1tcTGB9/iU2x+0uvs2ZhadQY9nxJS9oB+Hsajj3z8UOPGnigkMm52U84P7k2Bgpbgw0IK6OyIWC0jNSVLn6Yg== + use-subscription@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"