Skip to content

Instantly share code, notes, and snippets.

@luooooob
Last active February 8, 2023 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luooooob/902b4bb4962c9affb1e2cce5084c48ee to your computer and use it in GitHub Desktop.
Save luooooob/902b4bb4962c9affb1e2cce5084c48ee to your computer and use it in GitHub Desktop.
ColorScheme
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)
}
/* 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 }
}
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]
}
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