Options for selecting dark theme, fix some white flashes when in dark mode (#2722)

* add dark theme selection to settings/schema

* use `useThemePrefs` where needed

* adjust theme providers to support various themes

* update storybook

* handle web themes

* better themeing for web

* dont show dark theme prefs when color mode is light

* drop the inverted text change on oled theme

* get the color mode inside of `useColorModeTheme`

* use `ThemeName` type everywhere

* typo

* use dim/dark instead of dark/oled

* prevent any fickers on web

* fix styles

* use `dim` for dark default

* more cleanup

* 🤔

* set system background color

* ts
This commit is contained in:
Hailey 2024-02-06 11:43:51 -08:00 committed by GitHub
parent 856f80fc6d
commit ec86282403
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 251 additions and 172 deletions

View file

@ -1,57 +1,65 @@
import React from 'react'
import {isWeb} from '#/platform/detection'
import * as persisted from '#/state/persisted'
type StateContext = persisted.Schema['colorMode']
type SetContext = (v: persisted.Schema['colorMode']) => void
type StateContext = {
colorMode: persisted.Schema['colorMode']
darkTheme: persisted.Schema['darkTheme']
}
type SetContext = {
setColorMode: (v: persisted.Schema['colorMode']) => void
setDarkTheme: (v: persisted.Schema['darkTheme']) => void
}
const stateContext = React.createContext<StateContext>('system')
const setContext = React.createContext<SetContext>(
(_: persisted.Schema['colorMode']) => {},
)
const stateContext = React.createContext<StateContext>({
colorMode: 'system',
darkTheme: 'dark',
})
const setContext = React.createContext<SetContext>({} as SetContext)
export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = React.useState(persisted.get('colorMode'))
const [colorMode, setColorMode] = React.useState(persisted.get('colorMode'))
const [darkTheme, setDarkTheme] = React.useState(persisted.get('darkTheme'))
const setStateWrapped = React.useCallback(
(colorMode: persisted.Schema['colorMode']) => {
setState(colorMode)
persisted.write('colorMode', colorMode)
updateDocument(colorMode)
const setColorModeWrapped = React.useCallback(
(_colorMode: persisted.Schema['colorMode']) => {
setColorMode(_colorMode)
persisted.write('colorMode', _colorMode)
},
[setState],
[setColorMode],
)
const setDarkThemeWrapped = React.useCallback(
(_darkTheme: persisted.Schema['darkTheme']) => {
setDarkTheme(_darkTheme)
persisted.write('darkTheme', _darkTheme)
},
[setDarkTheme],
)
React.useEffect(() => {
updateDocument(persisted.get('colorMode')) // set on load
return persisted.onUpdate(() => {
setState(persisted.get('colorMode'))
updateDocument(persisted.get('colorMode'))
setColorModeWrapped(persisted.get('colorMode'))
setDarkThemeWrapped(persisted.get('darkTheme'))
})
}, [setState])
}, [setColorModeWrapped, setDarkThemeWrapped])
return (
<stateContext.Provider value={state}>
<setContext.Provider value={setStateWrapped}>
<stateContext.Provider value={{colorMode, darkTheme}}>
<setContext.Provider
value={{
setDarkTheme: setDarkThemeWrapped,
setColorMode: setColorModeWrapped,
}}>
{children}
</setContext.Provider>
</stateContext.Provider>
)
}
export function useColorMode() {
export function useThemePrefs() {
return React.useContext(stateContext)
}
export function useSetColorMode() {
export function useSetThemePrefs() {
return React.useContext(setContext)
}
function updateDocument(colorMode: string) {
if (isWeb && typeof window !== 'undefined') {
const html = window.document.documentElement
// remove any other color mode classes
html.className = html.className.replace(/colorMode--\w+/g, '')
html.classList.add(`colorMode--${colorMode}`)
}
}

View file

@ -14,7 +14,7 @@ export {
useSetDrawerSwipeDisabled,
} from './drawer-swipe-disabled'
export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode'
export {useColorMode, useSetColorMode} from './color-mode'
export {useThemePrefs, useSetThemePrefs} from './color-mode'
export {useOnboardingState, useOnboardingDispatch} from './onboarding'
export {useComposerState, useComposerControls} from './composer'
export {useTickEveryMinute} from './tick-every-minute'