forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 createContext,
3 type PropsWithChildren,
4 useContext,
5 useEffect,
6 useMemo,
7 useState,
8} from 'react'
9
10import * as persisted from '#/state/persisted'
11
12type StateContext = {
13 colorMode: persisted.Schema['colorMode']
14 darkTheme: persisted.Schema['darkTheme']
15 colorScheme: persisted.Schema['colorScheme']
16 hue: persisted.Schema['hue']
17}
18type SetContext = {
19 setColorMode: (v: persisted.Schema['colorMode']) => void
20 setDarkTheme: (v: persisted.Schema['darkTheme']) => void
21 setColorScheme: (v: persisted.Schema['colorScheme']) => void
22 setHue: (v: persisted.Schema['hue']) => void
23}
24
25const stateContext = createContext<StateContext>({
26 colorMode: 'system',
27 darkTheme: 'dark',
28 colorScheme: 'witchsky',
29 hue: 0,
30})
31stateContext.displayName = 'ColorModeStateContext'
32const setContext = createContext<SetContext>({} as SetContext)
33setContext.displayName = 'ColorModeSetContext'
34
35export function Provider({children}: PropsWithChildren<{}>) {
36 const [colorMode, setColorMode] = useState(() => persisted.get('colorMode'))
37 const [darkTheme, setDarkTheme] = useState(() => persisted.get('darkTheme'))
38 const [colorScheme, setColorScheme] = useState(persisted.get('colorScheme'))
39 const [hue, setHue] = useState(persisted.get('hue'))
40
41 const stateContextValue = useMemo(
42 () => ({
43 colorMode,
44 darkTheme,
45 colorScheme,
46 hue,
47 }),
48 [colorMode, darkTheme, colorScheme, hue],
49 )
50
51 const setContextValue = useMemo(
52 () => ({
53 setColorMode: (_colorMode: persisted.Schema['colorMode']) => {
54 setColorMode(_colorMode)
55 persisted.write('colorMode', _colorMode)
56 },
57 setDarkTheme: (_darkTheme: persisted.Schema['darkTheme']) => {
58 setDarkTheme(_darkTheme)
59 persisted.write('darkTheme', _darkTheme)
60 },
61 setColorScheme: (_colorScheme: persisted.Schema['colorScheme']) => {
62 setColorScheme(_colorScheme)
63 persisted.write('colorScheme', _colorScheme)
64 },
65 setHue: (_hue: persisted.Schema['hue']) => {
66 setHue(_hue)
67 persisted.write('hue', _hue)
68 },
69 }),
70 [],
71 )
72
73 useEffect(() => {
74 const unsub1 = persisted.onUpdate('darkTheme', nextDarkTheme => {
75 setDarkTheme(nextDarkTheme)
76 })
77 const unsub2 = persisted.onUpdate('colorMode', nextColorMode => {
78 setColorMode(nextColorMode)
79 })
80 const unsub3 = persisted.onUpdate('colorScheme', nextColorScheme => {
81 setColorScheme(nextColorScheme)
82 })
83 const unsub4 = persisted.onUpdate('hue', nextHue => {
84 setHue(nextHue)
85 })
86 return () => {
87 unsub1()
88 unsub2()
89 unsub3()
90 unsub4()
91 }
92 }, [])
93
94 return (
95 <stateContext.Provider value={stateContextValue}>
96 <setContext.Provider value={setContextValue}>
97 {children}
98 </setContext.Provider>
99 </stateContext.Provider>
100 )
101}
102
103export function useThemePrefs() {
104 return useContext(stateContext)
105}
106
107export function useSetThemePrefs() {
108 return useContext(setContext)
109}