An ATproto social media client -- with an independent Appview.
1import React from 'react'
2import {type ColorSchemeName, useColorScheme} from 'react-native'
3
4import {isWeb} from '#/platform/detection'
5import {useThemePrefs} from '#/state/shell'
6import {dark, dim, light} from '#/alf/themes'
7import {type ThemeName} from '#/alf/types'
8
9export function useColorModeTheme(): ThemeName {
10 const theme = useThemeName()
11
12 React.useLayoutEffect(() => {
13 updateDocument(theme)
14 }, [theme])
15
16 return theme
17}
18
19export function useThemeName(): ThemeName {
20 const colorScheme = useColorScheme()
21 const {colorMode, darkTheme} = useThemePrefs()
22
23 return getThemeName(colorScheme, colorMode, darkTheme)
24}
25
26function getThemeName(
27 colorScheme: ColorSchemeName,
28 colorMode: 'system' | 'light' | 'dark',
29 darkTheme?: ThemeName,
30) {
31 if (
32 (colorMode === 'system' && colorScheme === 'light') ||
33 colorMode === 'light'
34 ) {
35 return 'light'
36 } else {
37 return darkTheme ?? 'dim'
38 }
39}
40
41function updateDocument(theme: ThemeName) {
42 // @ts-ignore web only
43 if (isWeb && typeof window !== 'undefined') {
44 // @ts-ignore web only
45 const html = window.document.documentElement
46 // @ts-ignore web only
47 const meta = window.document.querySelector('meta[name="theme-color"]')
48
49 // remove any other color mode classes
50 html.className = html.className.replace(/(theme)--\w+/g, '')
51 html.classList.add(`theme--${theme}`)
52 html.style.backgroundColor = getBackgroundColor(theme)
53 // set color to 'theme-color' meta tag
54 meta?.setAttribute('content', getBackgroundColor(theme))
55 }
56}
57
58export function getBackgroundColor(theme: ThemeName): string {
59 switch (theme) {
60 case 'light':
61 return light.atoms.bg.backgroundColor
62 case 'dark':
63 return dark.atoms.bg.backgroundColor
64 case 'dim':
65 return dim.atoms.bg.backgroundColor
66 }
67}