1
- import { useEffect , useState } from 'react' ;
1
+ import { useCallback , useEffect , useState } from 'react' ;
2
2
import { BrowserRouter as Router , Routes , Route } from 'react-router-dom' ;
3
3
import 'semantic-ui-css/semantic.min.css' ;
4
4
import 'bootstrap/dist/css/bootstrap.min.css' ;
@@ -17,56 +17,72 @@ import AdminPage from './pages/AdminPage';
17
17
import ReviewsPage from './pages/ReviewsPage' ;
18
18
import SideBar from './component/SideBar/SideBar' ;
19
19
20
- import ThemeContext from './style/theme-context' ;
20
+ import ThemeContext , { Theme } from './style/theme-context' ;
21
21
import axios from 'axios' ;
22
22
import { useCookies } from 'react-cookie' ;
23
23
24
- function getDefaultDarkModeValue ( ) {
25
- switch ( localStorage . getItem ( 'theme' ) ) {
26
- case 'dark' :
27
- return true ;
28
- case 'light' :
29
- return false ;
30
- default :
31
- return window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
32
- }
24
+ function isSystemDark ( ) {
25
+ return window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
33
26
}
34
27
35
28
export default function App ( ) {
36
29
// default darkMode to local or system preferences
37
- const [ darkMode , setDarkMode ] = useState ( getDefaultDarkModeValue ( ) ) ;
30
+ const [ usingSystemTheme , setUsingSystemTheme ] = useState (
31
+ localStorage . getItem ( 'theme' ) === 'system' || ! localStorage . getItem ( 'theme' ) ,
32
+ ) ;
33
+ const [ darkMode , setDarkMode ] = useState (
34
+ usingSystemTheme ? isSystemDark ( ) : localStorage . getItem ( 'theme' ) === 'dark' ,
35
+ ) ;
38
36
const [ cookies ] = useCookies ( [ 'user' ] ) ;
39
37
38
+ /**
39
+ * Sets the theme state
40
+ * @param theme
41
+ */
42
+ const setThemeState = useCallback ( ( theme : Theme ) => {
43
+ if ( theme === 'system' ) {
44
+ setDarkMode ( isSystemDark ( ) ) ;
45
+ setUsingSystemTheme ( true ) ;
46
+ } else {
47
+ setDarkMode ( theme === 'dark' ) ;
48
+ setUsingSystemTheme ( false ) ;
49
+ }
50
+ } , [ ] ) ;
51
+
52
+ /**
53
+ * Sets the theme state and saves the users theme preference.
54
+ * Saves to account if logged in, local storage if not
55
+ * @param theme
56
+ */
57
+ const setTheme = ( theme : Theme ) => {
58
+ setThemeState ( theme ) ;
59
+ if ( cookies . user ) {
60
+ axios . post ( '/api/users/preferences' , { theme } ) ;
61
+ } else {
62
+ localStorage . setItem ( 'theme' , theme ) ;
63
+ }
64
+ } ;
65
+
40
66
useEffect ( ( ) => {
41
67
// if logged in, load user prefs (theme) from mongo
42
68
if ( cookies . user ) {
43
69
axios . get ( '/api/users/preferences' ) . then ( ( res ) => {
44
- const { theme } = res . data ;
45
- if ( theme === 'dark' ) {
46
- setDarkMode ( true ) ;
47
- } else if ( theme === 'light' ) {
48
- setDarkMode ( false ) ;
70
+ const { theme } : { theme ?: Theme } = res . data ;
71
+ if ( theme ) {
72
+ setThemeState ( theme ) ;
49
73
}
50
74
} ) ;
51
75
}
52
- } , [ cookies . user ] ) ;
76
+ } , [ cookies . user , setThemeState ] ) ;
53
77
54
78
useEffect ( ( ) => {
79
+ // Theme styling is controlled by data-theme attribute on body being set to light or dark
55
80
document . querySelector ( 'body' ) ! . setAttribute ( 'data-theme' , darkMode ? 'dark' : 'light' ) ;
56
- if ( cookies . user ) {
57
- axios . post ( '/api/users/preferences' , { theme : darkMode ? 'dark' : 'light' } ) ;
58
- } else {
59
- localStorage . setItem ( 'theme' , darkMode ? 'dark' : 'light' ) ;
60
- }
61
- } , [ cookies . user , darkMode ] ) ;
62
-
63
- const toggleTheme = ( ) => {
64
- setDarkMode ( ! darkMode ) ;
65
- } ;
81
+ } , [ darkMode ] ) ;
66
82
67
83
return (
68
84
< Router >
69
- < ThemeContext . Provider value = { { darkMode : darkMode , toggleTheme : toggleTheme } } >
85
+ < ThemeContext . Provider value = { { darkMode, usingSystemTheme , setTheme } } >
70
86
< AppHeader />
71
87
< div className = "app-body" >
72
88
< div className = "app-sidebar" >
0 commit comments