From d97e31bd3bcb142609eb008737607f25a9863fa1 Mon Sep 17 00:00:00 2001 From: Mathieu Marques Date: Sun, 20 Feb 2022 00:45:16 +0100 Subject: [PATCH] feat(theme): save the current theme in the local storage --- src/pages/_document.jsx | 2 +- src/theme/ThemeContext.tsx | 32 ++++++++++++++++++++++++-------- src/theme/constants.ts | 6 ++++++ src/theme/theme.ts | 6 +++--- 4 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 src/theme/constants.ts diff --git a/src/pages/_document.jsx b/src/pages/_document.jsx index e9775b39..219677e2 100644 --- a/src/pages/_document.jsx +++ b/src/pages/_document.jsx @@ -1,7 +1,7 @@ import React, { Children } from 'react'; import NextDocument, { Head, Html, Main, NextScript } from 'next/document'; import { ServerStyleSheets } from '@mui/styles'; -import { dark as theme } from '@/theme/theme'; +import { darkTheme as theme } from '@/theme/theme'; export default class Document extends NextDocument { static async getInitialProps(context) { diff --git a/src/theme/ThemeContext.tsx b/src/theme/ThemeContext.tsx index d8f2d094..b8cdaf86 100644 --- a/src/theme/ThemeContext.tsx +++ b/src/theme/ThemeContext.tsx @@ -2,33 +2,35 @@ import React, { FunctionComponent, ReactChild, createContext, + useEffect, useMemo, useState, } from 'react'; import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles'; -import { base, dark, light } from '@/theme/theme'; +import { THEME_STORAGE_KEY, Theme } from '@/theme/constants'; +import { baseTheme, darkTheme, lightTheme } from '@/theme/theme'; type Toggle = () => void; interface ThemeState { - isDark: boolean; + isDark: boolean | null; toggle: Toggle; } -const initialThemeState: ThemeState = { - isDark: true, +const initialState: ThemeState = { + isDark: null, // eslint-disable-next-line @typescript-eslint/no-empty-function toggle: () => {}, }; -export const ThemeContext = createContext(initialThemeState); +export const ThemeContext = createContext(initialState); interface Props { children: ReactChild | ReactChild[]; } export const ThemeProvider: FunctionComponent = ({ children }) => { - const [isDark, setIsDark] = useState(initialThemeState.isDark); + const [isDark, setIsDark] = useState(null); const toggle: Toggle = () => { setIsDark((previous) => !previous); @@ -36,10 +38,24 @@ export const ThemeProvider: FunctionComponent = ({ children }) => { const value: ThemeState = useMemo(() => ({ isDark, toggle }), [isDark]); + useEffect(() => { + if (isDark !== null) { + const value: Theme = isDark ? Theme.DARK : Theme.LIGHT; + window.localStorage.setItem(THEME_STORAGE_KEY, value); + } + }, [isDark]); + + useEffect(() => { + const value = window.localStorage.getItem(THEME_STORAGE_KEY); + setIsDark(value !== Theme.LIGHT); + }, []); + + if (isDark === null) return null; + return ( - - {children} + + {children} ); diff --git a/src/theme/constants.ts b/src/theme/constants.ts new file mode 100644 index 00000000..99de24f0 --- /dev/null +++ b/src/theme/constants.ts @@ -0,0 +1,6 @@ +export const THEME_STORAGE_KEY = 'ddftwiki:theme'; + +export enum Theme { + DARK = 'dark', + LIGHT = 'light', +} diff --git a/src/theme/theme.ts b/src/theme/theme.ts index 084cf7b8..babd1885 100644 --- a/src/theme/theme.ts +++ b/src/theme/theme.ts @@ -34,7 +34,7 @@ declare module '@mui/styles' { interface DefaultTheme extends Theme {} } -export const base: (theme: Theme) => Theme = (theme) => { +export const baseTheme: (theme: Theme) => Theme = (theme) => { const { breakpoints, palette, spacing, typography } = theme; const { mode } = palette; return createTheme({ @@ -136,7 +136,7 @@ export const base: (theme: Theme) => Theme = (theme) => { }); }; -export const dark: Theme = createTheme({ +export const darkTheme: Theme = createTheme({ palette: { background: { default: '#121212', paper: grey[900] }, mode: 'dark', @@ -145,7 +145,7 @@ export const dark: Theme = createTheme({ }, } as ThemeOptions); -export const light: Theme = createTheme({ +export const lightTheme: Theme = createTheme({ palette: { background: { default: grey[100] }, mode: 'light',