moved global state loic to separate file
- moved related types and interfaces too
This commit is contained in:
parent
1e645a14ca
commit
9861aeda7f
4 changed files with 95 additions and 30 deletions
29
src/App.tsx
29
src/App.tsx
|
@ -1,12 +1,9 @@
|
||||||
import { useEffect, useState } from "react"
|
import { useContext, useEffect, useState } from "react"
|
||||||
import { Routes, Route } from "react-router-dom"
|
import { Routes, Route } from "react-router-dom"
|
||||||
import styled, { ThemeProvider } from "styled-components"
|
import styled, { ThemeProvider } from "styled-components"
|
||||||
import { Helmet } from "react-helmet-async"
|
import { Helmet } from "react-helmet-async"
|
||||||
import storage from "local-storage-fallback"
|
|
||||||
import { isIE } from "react-device-detect"
|
import { isIE } from "react-device-detect"
|
||||||
|
|
||||||
import { ThemeType } from "../types/styled-components"
|
|
||||||
|
|
||||||
import Loading from "./components/Loading"
|
import Loading from "./components/Loading"
|
||||||
import Navbar from "./components/Navbar"
|
import Navbar from "./components/Navbar"
|
||||||
import Footer from "./components/Footer"
|
import Footer from "./components/Footer"
|
||||||
|
@ -20,6 +17,8 @@ import Portfolio from "./pages/Portfolio"
|
||||||
import theming from "./styles/theming"
|
import theming from "./styles/theming"
|
||||||
import GlobalStyle from "./styles/globalStyle"
|
import GlobalStyle from "./styles/globalStyle"
|
||||||
|
|
||||||
|
import { ActionsEnum, globalContext } from "./globalContext"
|
||||||
|
|
||||||
const IENotSupported = styled.p`
|
const IENotSupported = styled.p`
|
||||||
margin: auto;
|
margin: auto;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
|
@ -34,17 +33,12 @@ const StyledContentContainer = styled.div`
|
||||||
margin-top: 5rem;
|
margin-top: 5rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
const App = () => {
|
export default function App() {
|
||||||
|
const { globalState, dispatch } = useContext(globalContext)
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [currentTheme, setCurrentTheme] = useState<ThemeType>(
|
|
||||||
(storage.getItem("theme") || "dark") as ThemeType // get theme from storage and set to "dark" mode if not set already
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// set loading to false if all fonts are loaded
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// show loading screen until all fonts are loaded.
|
|
||||||
// Experimental feature. Not fully supported on all browsers (IE, I'm looking at you).
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet
|
|
||||||
|
|
||||||
// checks if document.fonts.onloadingdone is supported on the browser
|
// checks if document.fonts.onloadingdone is supported on the browser
|
||||||
if (typeof document.fonts.onloadingdone != undefined) {
|
if (typeof document.fonts.onloadingdone != undefined) {
|
||||||
document.fonts.onloadingdone = () => {
|
document.fonts.onloadingdone = () => {
|
||||||
|
@ -55,11 +49,6 @@ const App = () => {
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// save theme when it is changed
|
|
||||||
storage.setItem("theme", currentTheme)
|
|
||||||
}, [currentTheme])
|
|
||||||
|
|
||||||
if (isIE)
|
if (isIE)
|
||||||
return (
|
return (
|
||||||
<IENotSupported>
|
<IENotSupported>
|
||||||
|
@ -70,9 +59,9 @@ const App = () => {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider
|
<ThemeProvider
|
||||||
theme={{
|
theme={{
|
||||||
currentTheme: currentTheme,
|
currentTheme: globalState.theme,
|
||||||
setTheme(setThemeTo) {
|
setTheme(setThemeTo) {
|
||||||
setCurrentTheme(setThemeTo)
|
dispatch({ type: ActionsEnum.UPDATE_THEME, payload: setThemeTo })
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -104,5 +93,3 @@ const App = () => {
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
|
||||||
|
|
76
src/globalContext.tsx
Normal file
76
src/globalContext.tsx
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { createContext, useEffect, useReducer } from "react"
|
||||||
|
import storage from "local-storage-fallback"
|
||||||
|
|
||||||
|
import type { Dispatch, ReactNode, ReactElement } from "react"
|
||||||
|
|
||||||
|
export type SiteLocale = "en" | "kr"
|
||||||
|
export type SiteTheme = "dark" | "light"
|
||||||
|
|
||||||
|
export enum ActionsEnum {
|
||||||
|
UPDATE_THEME,
|
||||||
|
UPDATE_LOCALE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGlobalState {
|
||||||
|
locale: SiteLocale
|
||||||
|
theme: SiteTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalAction =
|
||||||
|
| {
|
||||||
|
type: ActionsEnum.UPDATE_THEME
|
||||||
|
payload: SiteTheme
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: ActionsEnum.UPDATE_LOCALE
|
||||||
|
payload: SiteLocale
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGlobalContext {
|
||||||
|
globalState: IGlobalState
|
||||||
|
dispatch: Dispatch<GlobalAction>
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultState: IGlobalState = {
|
||||||
|
locale: (storage.getItem("locale") || "en") as SiteLocale,
|
||||||
|
theme: (storage.getItem("theme") || "dark") as SiteTheme,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const globalContext = createContext({} as IGlobalContext)
|
||||||
|
|
||||||
|
function reducer(state = defaultState, action: GlobalAction): IGlobalState {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionsEnum.UPDATE_THEME:
|
||||||
|
state.theme = action.payload
|
||||||
|
break
|
||||||
|
|
||||||
|
case ActionsEnum.UPDATE_LOCALE:
|
||||||
|
state.locale = action.payload
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...state }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GlobalStore(props: { children: ReactNode }): ReactElement {
|
||||||
|
const [globalState, dispatch] = useReducer(reducer, defaultState)
|
||||||
|
|
||||||
|
// save theme when it is changed
|
||||||
|
useEffect(() => {
|
||||||
|
storage.setItem("theme", globalState.theme)
|
||||||
|
}, [globalState.theme])
|
||||||
|
|
||||||
|
// save locale when it is changed
|
||||||
|
useEffect(() => {
|
||||||
|
storage.setItem("locale", globalState.locale)
|
||||||
|
}, [globalState.locale])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<globalContext.Provider value={{ globalState, dispatch }}>
|
||||||
|
{props.children}
|
||||||
|
</globalContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
|
@ -2,16 +2,19 @@ import React from "react"
|
||||||
import ReactDOM from "react-dom"
|
import ReactDOM from "react-dom"
|
||||||
import { HelmetProvider } from "react-helmet-async"
|
import { HelmetProvider } from "react-helmet-async"
|
||||||
import { BrowserRouter } from "react-router-dom"
|
import { BrowserRouter } from "react-router-dom"
|
||||||
|
import { GlobalStore } from "./globalContext"
|
||||||
|
|
||||||
import App from "./App"
|
import App from "./App"
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<GlobalStore>
|
||||||
<HelmetProvider>
|
<BrowserRouter>
|
||||||
<App />
|
<HelmetProvider>
|
||||||
</HelmetProvider>
|
<App />
|
||||||
</BrowserRouter>
|
</HelmetProvider>
|
||||||
|
</BrowserRouter>
|
||||||
|
</GlobalStore>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById("root")
|
document.getElementById("root")
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import "styled-components"
|
import "styled-components"
|
||||||
|
import type { SiteTheme } from "../src/globalContext"
|
||||||
export type ThemeType = "dark" | "light"
|
|
||||||
|
|
||||||
declare module "styled-components" {
|
declare module "styled-components" {
|
||||||
export interface DefaultTheme {
|
export interface DefaultTheme {
|
||||||
currentTheme: ThemeType
|
currentTheme: SiteTheme
|
||||||
setTheme(setThemeTo: ThemeType): void
|
setTheme(setThemeTo: SiteTheme): void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue