Started on settings page

main
guusvanmeerveld 2 years ago
parent 935c1df0ab
commit 0edd0afb2a

@ -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",

@ -0,0 +1,7 @@
interface Settings {
theme?: "light" | "dark";
primaryColor: string;
accentColor: string;
}
export default Settings;

@ -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 (
<QueryClientProvider client={queryClient}>

@ -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 (
<Box sx={{ my: 3, display: "flex" }}>
<Typography variant="h5" sx={{ flexGrow: 1 }}>
{type}
</Typography>
{[
blue[800],
red[800],
green[800],
cyan[800],
purple[800],
yellow[800],
orange[800]
].map((color) => (
<Box
onClick={() => 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
}}
/>
))}
</Box>
);
};
return (
<Layout>
<Container>
<Typography sx={{ my: 2 }} variant="h2">
Settings
</Typography>
<Divider sx={{ mb: 4 }} />
<Typography variant="h4">Theme</Typography>
<Box sx={{ my: 3, display: "flex" }}>
<Typography variant="h5" sx={{ flexGrow: 1 }}>
General theme
</Typography>
<ButtonGroup
variant="contained"
color="primary"
aria-label="outlined default button group"
>
<Button onClick={() => setSetting("theme", "light")}>Light</Button>
<Button onClick={() => setSetting("theme")}>System</Button>
<Button onClick={() => setSetting("theme", "dark")}>Dark</Button>
</ButtonGroup>
</Box>
<ColorSetting type="Primary Color" />
<ColorSetting type="Accent Color" />
<Divider sx={{ my: 4 }} />
<Typography variant="h4">Player</Typography>
<Divider sx={{ my: 4 }} />
<Typography variant="h4">Miscellaneous</Typography>
</Container>
</Layout>
);
};
export default Settings;

@ -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
}
}
});

@ -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<SetStateAction<Settings>>
] => {
const [settings, setSettings] = useLocalStorageState<Settings>("settings", {
defaultValue: defaultSettings,
ssr: false
});
return [settings, setSettings];
};

@ -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, "");

@ -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"

Loading…
Cancel
Save