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 material3Accent: persisted.Schema['material3Accent']
18 material3Style: persisted.Schema['material3Style']
19}
20type SetContext = {
21 setColorMode: (v: persisted.Schema['colorMode']) => void
22 setDarkTheme: (v: persisted.Schema['darkTheme']) => void
23 setColorScheme: (v: persisted.Schema['colorScheme']) => void
24 setHue: (v: persisted.Schema['hue']) => void
25 setMaterial3Accent: (v: persisted.Schema['material3Accent']) => void
26 setMaterial3Style: (v: persisted.Schema['material3Style']) => void
27}
28
29const stateContext = createContext<StateContext>({
30 colorMode: 'system',
31 darkTheme: 'dark',
32 colorScheme: 'witchsky',
33 hue: 0,
34 material3Accent: '#ee6300',
35 material3Style: 'TONAL_SPOT',
36})
37stateContext.displayName = 'ColorModeStateContext'
38const setContext = createContext<SetContext>({} as SetContext)
39setContext.displayName = 'ColorModeSetContext'
40
41export function Provider({children}: PropsWithChildren<{}>) {
42 const [colorMode, setColorMode] = useState(() => persisted.get('colorMode'))
43 const [darkTheme, setDarkTheme] = useState(() => persisted.get('darkTheme'))
44 const [colorScheme, setColorScheme] = useState(() =>
45 persisted.get('colorScheme'),
46 )
47 const [hue, setHue] = useState(() => persisted.get('hue'))
48 const [material3Accent, setMaterial3Accent] = useState(
49 () => persisted.get('material3Accent') ?? '#ee6300',
50 )
51 const [material3Style, setMaterial3Style] = useState(
52 () => persisted.get('material3Style') ?? 'TONAL_SPOT',
53 )
54
55 const stateContextValue = useMemo(
56 () => ({
57 colorMode,
58 darkTheme,
59 colorScheme,
60 hue,
61 material3Accent,
62 material3Style,
63 }),
64 [colorMode, darkTheme, colorScheme, hue, material3Accent, material3Style],
65 )
66
67 const setContextValue = useMemo(
68 () => ({
69 setColorMode: (_colorMode: persisted.Schema['colorMode']) => {
70 setColorMode(_colorMode)
71 void persisted.write('colorMode', _colorMode)
72 },
73 setDarkTheme: (_darkTheme: persisted.Schema['darkTheme']) => {
74 setDarkTheme(_darkTheme)
75 void persisted.write('darkTheme', _darkTheme)
76 },
77 setColorScheme: (_colorScheme: persisted.Schema['colorScheme']) => {
78 setColorScheme(_colorScheme)
79 void persisted.write('colorScheme', _colorScheme)
80 },
81 setHue: (_hue: persisted.Schema['hue']) => {
82 setHue(_hue)
83 void persisted.write('hue', _hue)
84 },
85 setMaterial3Accent: (
86 _material3Accent: persisted.Schema['material3Accent'],
87 ) => {
88 setMaterial3Accent(_material3Accent)
89 void persisted.write('material3Accent', _material3Accent)
90 },
91 setMaterial3Style: (_material3Style: persisted.Schema['material3Style']) => {
92 setMaterial3Style(_material3Style)
93 void persisted.write('material3Style', _material3Style)
94 },
95 }),
96 [],
97 )
98
99 useEffect(() => {
100 const unsub1 = persisted.onUpdate('darkTheme', nextDarkTheme => {
101 setDarkTheme(nextDarkTheme)
102 })
103 const unsub2 = persisted.onUpdate('colorMode', nextColorMode => {
104 setColorMode(nextColorMode)
105 })
106 const unsub3 = persisted.onUpdate('colorScheme', nextColorScheme => {
107 setColorScheme(nextColorScheme)
108 })
109 const unsub4 = persisted.onUpdate('hue', nextHue => {
110 setHue(nextHue)
111 })
112 const unsub5 = persisted.onUpdate(
113 'material3Accent',
114 nextMaterial3Accent => {
115 setMaterial3Accent(nextMaterial3Accent)
116 },
117 )
118 const unsub6 = persisted.onUpdate(
119 'material3Style',
120 nextMaterial3Style => {
121 setMaterial3Style(nextMaterial3Style)
122 },
123 )
124 return () => {
125 unsub1()
126 unsub2()
127 unsub3()
128 unsub4()
129 unsub5()
130 unsub6()
131 }
132 }, [])
133
134 return (
135 <stateContext.Provider value={stateContextValue}>
136 <setContext.Provider value={setContextValue}>
137 {children}
138 </setContext.Provider>
139 </stateContext.Provider>
140 )
141}
142
143export function useThemePrefs() {
144 return useContext(stateContext)
145}
146
147export function useSetThemePrefs() {
148 return useContext(setContext)
149}