mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-08 07:56:12 +02:00
feat: added prefers-color-scheme support
+ read media query for theme preference + improved typing of useLocalStorage hook
This commit is contained in:
committed by
Jean-Philippe Sirois
parent
32c12cba77
commit
6b267780b5
+35
-6
@@ -1,12 +1,13 @@
|
|||||||
import React, { createContext, FC, useMemo } from "react"
|
import React, { createContext, FC, useEffect, useMemo, useState } from "react"
|
||||||
import { ThemeProvider as BaseThemeProvider } from "styled-components"
|
import { ThemeProvider as BaseThemeProvider } from "styled-components"
|
||||||
|
|
||||||
import { darkTheme, lightTheme } from "./design/themes"
|
import { darkTheme, lightTheme } from "./design/themes"
|
||||||
import { useLocalStorage } from "./hooks/useLocalStorage"
|
import { useLocalStorage } from "./hooks/useLocalStorage"
|
||||||
|
|
||||||
|
type ThemeType = "dark" | "light"
|
||||||
|
|
||||||
export interface IThemeContext {
|
export interface IThemeContext {
|
||||||
theme: "dark" | "light"
|
theme: ThemeType
|
||||||
setTheme: () => void
|
|
||||||
toggleTheme: () => void
|
toggleTheme: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,19 +18,47 @@ interface IScopedDownChildren {
|
|||||||
export const ThemeContext = createContext<IThemeContext | null>(null)
|
export const ThemeContext = createContext<IThemeContext | null>(null)
|
||||||
|
|
||||||
const ThemeProvider: FC<IScopedDownChildren> = ({ children }) => {
|
const ThemeProvider: FC<IScopedDownChildren> = ({ children }) => {
|
||||||
const [theme, setTheme] = useLocalStorage("theme", "dark")
|
// User's explicitly set theme
|
||||||
|
const [localTheme, setLocalTheme] = useLocalStorage<ThemeType | "unset">(
|
||||||
|
"theme",
|
||||||
|
"unset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App's current theme
|
||||||
|
const [theme, setTheme] = useState<ThemeType>(
|
||||||
|
localTheme === "unset" ? "dark" : localTheme
|
||||||
|
)
|
||||||
|
|
||||||
const themeObject = useMemo(
|
const themeObject = useMemo(
|
||||||
() => (theme === "dark" ? darkTheme : lightTheme),
|
() => (theme === "dark" ? darkTheme : lightTheme),
|
||||||
[theme]
|
[theme]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (localTheme === "unset") {
|
||||||
|
const prefersLightTheme = window.matchMedia(
|
||||||
|
"(prefers-color-scheme: light)"
|
||||||
|
)
|
||||||
|
|
||||||
|
setTheme(prefersLightTheme.matches ? "light" : "dark")
|
||||||
|
|
||||||
|
prefersLightTheme.onchange = ({ matches }) =>
|
||||||
|
setTheme(matches ? "light" : "dark")
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
prefersLightTheme.onchange = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const contextValue = useMemo(
|
const contextValue = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
|
||||||
toggleTheme: () => {
|
toggleTheme: () => {
|
||||||
setTheme(theme === "light" ? "dark" : "light")
|
const newTheme = theme === "light" ? "dark" : "light"
|
||||||
|
setTheme(newTheme)
|
||||||
|
setLocalTheme(newTheme)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[theme, setTheme]
|
[theme, setTheme]
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
/* globals window */
|
/* globals window */
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
export const useLocalStorage = (name: string, initialValue: string) => {
|
export const useLocalStorage = <Value extends unknown = unknown>(
|
||||||
|
name: string,
|
||||||
|
initialValue: Value
|
||||||
|
) => {
|
||||||
const windowGlobal = typeof window !== "undefined" && window
|
const windowGlobal = typeof window !== "undefined" && window
|
||||||
const [value, setValue] = useState(() => {
|
|
||||||
|
const [value, setValue] = useState<Value>(() => {
|
||||||
if (windowGlobal) {
|
if (windowGlobal) {
|
||||||
const currentValue = windowGlobal.localStorage.getItem(name)
|
const currentValue = windowGlobal.localStorage.getItem(name)
|
||||||
return currentValue ? JSON.parse(currentValue) : initialValue
|
return currentValue ? JSON.parse(currentValue) : initialValue
|
||||||
@@ -17,5 +21,5 @@ export const useLocalStorage = (name: string, initialValue: string) => {
|
|||||||
}
|
}
|
||||||
}, [name, value, windowGlobal])
|
}, [name, value, windowGlobal])
|
||||||
|
|
||||||
return [value, setValue]
|
return [value, setValue] as const
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user