diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 500a7b67d..028f47ef5 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -20,7 +20,7 @@ import PublicLayout from 'soapbox/features/public_layout'; import NotificationsContainer from 'soapbox/features/ui/containers/notifications_container'; import WaitlistPage from 'soapbox/features/verification/waitlist_page'; import { createGlobals } from 'soapbox/globals'; -import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings } from 'soapbox/hooks'; +import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { generateThemeCss } from 'soapbox/utils/theme'; @@ -82,17 +82,12 @@ const SoapboxMount = () => { const [localeLoading, setLocaleLoading] = useState(true); const [isLoaded, setIsLoaded] = useState(false); - const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)'); - const [isSystemDarkMode, setSystemDarkMode] = useState(colorSchemeQueryList.matches); + const systemTheme = useSystemTheme(); const userTheme = settings.get('themeMode'); - const darkMode = userTheme === 'dark' || (userTheme === 'system' && isSystemDarkMode); + const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); const themeCss = generateThemeCss(soapboxConfig); - const handleSystemModeChange = (event: MediaQueryListEvent) => { - setSystemDarkMode(event.matches); - }; - // Load the user's locale useEffect(() => { MESSAGES[locale]().then(messages => { @@ -110,12 +105,6 @@ const SoapboxMount = () => { }); }, []); - useEffect(() => { - colorSchemeQueryList.addEventListener('change', handleSystemModeChange); - - return () => colorSchemeQueryList.removeEventListener('change', handleSystemModeChange); - }, []); - // @ts-ignore: I don't actually know what these should be, lol const shouldUpdateScroll = (prevRouterProps, { location }) => { return !(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey); diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index 0c6698988..66fd31059 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -6,3 +6,4 @@ export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; export { useSettings } from './useSettings'; export { useSoapboxConfig } from './useSoapboxConfig'; +export { useSystemTheme } from './useSystemTheme'; diff --git a/app/soapbox/hooks/useSystemTheme.ts b/app/soapbox/hooks/useSystemTheme.ts new file mode 100644 index 000000000..3258851f5 --- /dev/null +++ b/app/soapbox/hooks/useSystemTheme.ts @@ -0,0 +1,21 @@ +import { useState, useEffect } from 'react'; + +type SystemTheme = 'light' | 'dark'; + +/** Get the system color scheme of the system. */ +export const useSystemTheme = (): SystemTheme => { + const query = window.matchMedia('(prefers-color-scheme: dark)'); + const [dark, setDark] = useState(query.matches); + + const handleChange = (event: MediaQueryListEvent) => { + setDark(event.matches); + }; + + useEffect(() => { + query.addEventListener('change', handleChange); + + return () => query.removeEventListener('change', handleChange); + }, []); + + return dark ? 'dark' : 'light'; +};