このコミットが含まれているのは:
2026-07-04 19:03:50 +09:00
コミット 6a57dc53bf
22個のファイルの変更1099行の追加114行の削除
+111
ファイルの表示
@@ -0,0 +1,111 @@
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
import { DEFAULT_USER_SETTINGS, fetchUserSettings } from '@/lib/settings'
import type { Dispatch, FC, ReactNode, SetStateAction } from 'react'
import type { User } from '@/types'
import type { UserSettings } from '@/lib/settings'
type ContextValue = {
loaded: boolean
settings: UserSettings
setSettings: Dispatch<SetStateAction<UserSettings>> }
const UserSettingsContext = createContext<ContextValue | null> (null)
const applyTheme = (theme: UserSettings['theme']) => {
const root = document.documentElement
const media = window.matchMedia ('(prefers-color-scheme: dark)')
const sync = () => {
const dark = theme === 'dark' || (theme === 'system' && media.matches)
root.classList.toggle ('dark', dark)
root.style.colorScheme = dark ? 'dark' : 'light'
}
sync ()
if (theme !== 'system')
return () => { }
const onChange = () => sync ()
media.addEventListener ('change', onChange)
return () => {
media.removeEventListener ('change', onChange)
}
}
export const UserSettingsProvider: FC<{
children: ReactNode
user: User | null }> = ({ children, user }) => {
const [loaded, setLoaded] = useState (false)
const [settings, setSettings] = useState<UserSettings> (DEFAULT_USER_SETTINGS)
useEffect (() => {
let cancelled = false
if (!(user))
{
setSettings (DEFAULT_USER_SETTINGS)
setLoaded (true)
return
}
setLoaded (false)
void (async () => {
try
{
const next = await fetchUserSettings ()
if (!(cancelled))
{
setSettings (next)
setLoaded (true)
}
}
catch
{
if (!(cancelled))
{
setSettings (DEFAULT_USER_SETTINGS)
setLoaded (true)
}
}
}) ()
return () => {
cancelled = true
}
}, [user])
useEffect (() => applyTheme (settings.theme), [settings.theme])
useEffect (() => {
document.documentElement.dataset.displayDensity = settings.displayDensity
document.documentElement.dataset.fontSize = settings.fontSize
}, [settings.displayDensity, settings.fontSize])
const value = useMemo<ContextValue> (() => ({
loaded,
settings,
setSettings,
}), [loaded, settings])
return (
<UserSettingsContext.Provider value={value}>
{children}
</UserSettingsContext.Provider>)
}
export const useUserSettings = (): ContextValue => {
const value = useContext (UserSettingsContext)
if (value == null)
throw new Error ('UserSettingsProvider is missing')
return value
}