From 3255e47033af367fc2a9a2b94996409478eeb0f3 Mon Sep 17 00:00:00 2001 From: Alexandru Bereghici Date: Wed, 3 Nov 2021 15:07:48 +0200 Subject: [PATCH] feat: automatically switch theme when system color preference changes (#40) --- apps/blog/package.json | 2 +- .../theme/src/theme-provider.tsx | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/blog/package.json b/apps/blog/package.json index f6c2287..7032c92 100644 --- a/apps/blog/package.json +++ b/apps/blog/package.json @@ -4,7 +4,7 @@ "scripts": { "dev": "prisma generate && next dev", "build": "prisma generate && next build", - "start": "next start", + "start": "prisma generate && next start", "lint": "bereghici-scripts lint './src/**/*.{js,jsx,ts,tsx}'", "pre-commit": "bereghici-scripts pre-commit", "typecheck": "bereghici-scripts typecheck", diff --git a/packages/design-system/theme/src/theme-provider.tsx b/packages/design-system/theme/src/theme-provider.tsx index ca51f67..d651b30 100644 --- a/packages/design-system/theme/src/theme-provider.tsx +++ b/packages/design-system/theme/src/theme-provider.tsx @@ -22,11 +22,6 @@ const ThemeContext = function ThemeProvider({ children }: { children: React.ReactNode }) { const [themeName, setThemeName] = React.useState('light'); - React.useEffect(() => { - const colorMode = window.document.body.getAttribute(THEME_DATA_ATTRIBUTE); - setThemeName(colorMode === 'dark' ? 'dark' : 'light'); - }, []); - const setTheme = React.useCallback((newThemeName: ThemeTypes) => { localStorage.set(THEME_STORAGE_KEY, newThemeName); document.body.setAttribute(THEME_DATA_ATTRIBUTE, newThemeName); @@ -38,6 +33,26 @@ function ThemeProvider({ children }: { children: React.ReactNode }) { [themeName, setTheme] ); + React.useEffect(() => { + const colorMode = window.document.body.getAttribute(THEME_DATA_ATTRIBUTE); + setThemeName(colorMode === 'dark' ? 'dark' : 'light'); + }, []); + + React.useEffect(() => { + const onThemeChange = (e: MediaQueryListEvent) => { + const colorPreference = e.matches ? 'dark' : 'light'; + + setTheme(colorPreference); + }; + + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + mql.addEventListener('change', onThemeChange); + + return () => { + mql.removeEventListener('change', onThemeChange); + }; + }, [setTheme]); + return ( <>