Last active
February 8, 2023 17:26
-
-
Save luooooob/902b4bb4962c9affb1e2cce5084c48ee to your computer and use it in GitHub Desktop.
ColorScheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const systemColorSchemeRange = ['light', 'dark'] as const | |
const getMediaByColorScheme = (colorScheme: string): MediaQueryList => { | |
return matchMedia(`(prefers-color-scheme: ${colorScheme})`) | |
} | |
export const getSystemColorScheme = (): (typeof systemColorSchemeRange)[number] | null => { | |
return systemColorSchemeRange.find(colorScheme => getMediaByColorScheme(colorScheme).matches) || null | |
} | |
export const getSystemColorSchemeMedias = (): MediaQueryList[] => { | |
return systemColorSchemeRange.map(colorScheme => getMediaByColorScheme(colorScheme)) | |
} | |
export const getColorSchemeFromLocalStorage = (localStorageKey: string): string | null => { | |
return localStorage.getItem(localStorageKey) | |
} | |
export const setColorSchemeToLocalStorage = (localStorageKey: string, colorScheme: string): void => { | |
colorScheme | |
? localStorage.setItem(localStorageKey, colorScheme) | |
: localStorage.removeItem(localStorageKey) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable react-hooks/rules-of-hooks */ | |
import { createContext, ReactNode, useContext, useEffect, useMemo, useState } from "react" | |
import type { Dispatch, FC } from "react" | |
const LOCALSTORAGE_KEY = "diandiandian-user-perfers-color-scheme" | |
type ColorScheme = string | null | |
type ColorSchemeDispatch = Dispatch<ColorScheme> | |
const useSysColorScheme = () => { | |
if (typeof window === 'undefined') { | |
return { sysColorScheme: null } | |
} | |
const avaliableSysColorScheme = ["dark", "light"] as const | |
const mediasMap = { | |
["dark"]: window.matchMedia(`(prefers-color-scheme: dark`), | |
["light"]: window.matchMedia(`(prefers-color-scheme: light`) | |
} satisfies Record<typeof avaliableSysColorScheme[number], MediaQueryList> | |
const findSysColorScheme = (): ColorScheme => { | |
return avaliableSysColorScheme.find(key => | |
mediasMap[key].matches | |
) || null | |
} | |
const [sysColorScheme, setSysColorScheme] = useState(findSysColorScheme()) | |
useEffect(() => { | |
const onMediaChange = () => { | |
const newColorScheme = findSysColorScheme() | |
if (sysColorScheme !== newColorScheme) { | |
setSysColorScheme(newColorScheme) | |
} | |
} | |
const medias = avaliableSysColorScheme.map(key => mediasMap[key]) | |
medias.forEach(media => media.addEventListener('change', onMediaChange)) | |
return () => medias.forEach(media => media.removeEventListener('change', onMediaChange)) | |
}) | |
return { sysColorScheme } | |
} | |
const useUserColorScheme = () => { | |
if (typeof window === 'undefined') { | |
return { | |
userColorScheme: null, | |
setUserColorSchemeAndSave: () => { }, | |
} | |
} | |
const [userColorScheme, setUserColorScheme] = useState<ColorScheme>( | |
window.localStorage.getItem(LOCALSTORAGE_KEY) | |
) | |
const setUserColorSchemeAndSave: ColorSchemeDispatch = (colorScheme: ColorScheme) => { | |
setUserColorScheme(colorScheme) | |
if(colorScheme) { | |
window.localStorage.setItem(LOCALSTORAGE_KEY, colorScheme) | |
} | |
window.localStorage.removeItem(LOCALSTORAGE_KEY) | |
} | |
return { userColorScheme, setUserColorSchemeAndSave } | |
} | |
const ColorSchemeContext = createContext<ColorScheme>(null) | |
const ColorSchemeDispatchContext = createContext<ColorSchemeDispatch | null>(null) | |
type ColorSchemeProps = { | |
children: ReactNode | |
} | |
export const ColorScheme:FC<ColorSchemeProps> = ({ children }) => { | |
const { sysColorScheme } = useSysColorScheme() | |
const { userColorScheme, setUserColorSchemeAndSave } = useUserColorScheme() | |
const colorScheme = userColorScheme ?? sysColorScheme | |
return ( | |
<ColorSchemeContext.Provider value={colorScheme}> | |
<ColorSchemeDispatchContext.Provider value={setUserColorSchemeAndSave}> | |
{children} | |
</ColorSchemeDispatchContext.Provider> | |
</ColorSchemeContext.Provider> | |
) | |
} | |
export const useColorScheme = () => { | |
const colorScheme = useContext(ColorSchemeContext) | |
const setColorScheme = useContext(ColorSchemeDispatchContext) | |
if (!setColorScheme) { | |
throw new Error("") | |
} | |
return { colorScheme, setColorScheme } | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from "react" | |
import { | |
getSystemColorScheme, | |
getSystemColorSchemeMedias, | |
getColorSchemeFromLocalStorage, | |
setColorSchemeToLocalStorage | |
} from "../tools/colorScheme" | |
export const useSystemPrefersColorScheme = () => { | |
const initialColorScheme = getSystemColorScheme() | |
const [systemPrefersColorScheme, setSystemPrefersColorScheme] = useState(initialColorScheme) | |
const onMediaChange = () => { | |
const newColorScheme = getSystemColorScheme() | |
if (systemPrefersColorScheme !== newColorScheme) { | |
setSystemPrefersColorScheme(newColorScheme) | |
} | |
} | |
useEffect(() => { | |
const medias = getSystemColorSchemeMedias() | |
medias.forEach(media => media.addEventListener('change', onMediaChange)) | |
return () => medias.forEach(media => media.removeEventListener('change', onMediaChange)) | |
}) | |
return [systemPrefersColorScheme] | |
} | |
export const useUserPrefersColorScheme = (localStorageKey?: string) => { | |
const initialColorScheme = localStorageKey | |
? getColorSchemeFromLocalStorage(localStorageKey) | |
: null | |
const [userPrefersColorScheme, _setUserPrefersColorScheme] = useState(initialColorScheme) | |
const setUserPrefersColorScheme = (coloeScheme: string) => { | |
_setUserPrefersColorScheme(coloeScheme) | |
localStorageKey && setColorSchemeToLocalStorage(localStorageKey, coloeScheme) | |
} | |
return [userPrefersColorScheme, setUserPrefersColorScheme] | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getSystemColorScheme, getColorSchemeFromLocalStorage } from "./tools/colorScheme" | |
const backgroundColorScheme: string = | |
getSystemColorScheme() | |
|| getColorSchemeFromLocalStorage('user-prefers-background-color-scheme') | |
|| 'light' | |
const themeColorScheme: string = | |
getColorSchemeFromLocalStorage('user-prefers-theme-color-scheme') | |
|| 'jiaran' | |
document.documentElement.setAttribute('data-background-color-scheme', backgroundColorScheme) | |
document.documentElement.setAttribute('data-theme-color-scheme', themeColorScheme) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment