Franknoirot/live system theme (#358)

* Only show the Replay Onboarding button in file settings
Resolves #351. Eventually we will implement more sophisticated
logic for which settings should be shown where.

Signed-off-by: Frank Noirot <frank@kittycad.io>

* Remove unnecessary console.log

Signed-off-by: Frank Noirot <frank@kittycad.io>

* Respond to system theme changes in real-time
If the user has their "theme" setting to "system".
I tried to use the [XState invoked callback approach](https://xstate.js.org/docs/guides/communication.html#invoking-callbacks),
but I could not find any way to respond to the latest context/state values within the
media listener; I kept receiving stale state.

Signed-off-by: Frank Noirot <frank@kittycad.io>

---------

Signed-off-by: Frank Noirot <frank@kittycad.io>
This commit is contained in:
Frank Noirot
2023-08-31 09:34:13 -04:00
committed by GitHub
parent 9cbc088ba3
commit 798cbe968a
5 changed files with 42 additions and 14 deletions

View File

@ -15,7 +15,7 @@ import {
settingsMachine,
} from 'machines/settingsMachine'
import { toast } from 'react-hot-toast'
import { setThemeClass } from 'lib/theme'
import { setThemeClass, Themes } from 'lib/theme'
import {
AnyStateMachine,
ContextFrom,
@ -87,10 +87,21 @@ export const GlobalStateProvider = ({
commandBarMeta: settingsCommandBarMeta,
})
useEffect(
() => setThemeClass(settingsState.context.theme),
[settingsState.context.theme]
)
// Listen for changes to the system theme and update the app theme accordingly
// This is only done if the theme setting is set to 'system'.
// It can't be done in XState (in an invoked callback, for example)
// because there doesn't seem to be a good way to listen to
// events outside of the machine that also depend on the machine's context
useEffect(() => {
const matcher = window.matchMedia('(prefers-color-scheme: dark)')
const listener = (e: MediaQueryListEvent) => {
if (settingsState.context.theme !== 'system') return
setThemeClass(e.matches ? Themes.Dark : Themes.Light)
}
matcher.addEventListener('change', listener)
return () => matcher.removeEventListener('change', listener)
}, [settingsState.context])
// Auth machine setup
const [authState, authSend] = useMachine(authMachine, {