mirror of
				https://github.com/jakejarvis/jarv.is.git
				synced 2025-10-30 00:55:49 -04:00 
			
		
		
		
	clean up ThemeContext
				
					
				
			This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| import { createContext, useCallback, useEffect, useState, useRef } from "react"; | ||||
| import { createContext, useCallback, useEffect, useState } from "react"; | ||||
| import { useLocalStorage } from "react-use"; | ||||
| import { darkModeQuery, themeStorageKey } from "../lib/config/themes"; | ||||
| import type { Context, PropsWithChildren } from "react"; | ||||
| @@ -26,69 +26,64 @@ export const ThemeProvider = ({ | ||||
|   classNames: { | ||||
|     [themeName: string]: string; | ||||
|   }; | ||||
|   /** Optionally set `color-scheme` CSS property to change browser appearance. */ | ||||
|   enableColorScheme?: boolean; | ||||
| }>) => { | ||||
|   // keep track of if/when the user has set their theme *here*: | ||||
|   const [preferredTheme, setPreferredTheme] = useLocalStorage(themeStorageKey, null, { raw: true }); | ||||
|   // save the end result no matter how we got there (by preference or by system): | ||||
|   const [resolvedTheme, setResolvedTheme] = useState(""); | ||||
|   // TODO: remove this and do related stuff more gracefully | ||||
|   const validThemes = Object.keys(classNames); | ||||
|   // get the theme names (light, dark) via passed-in classnames' keys | ||||
|   const themeNames = Object.keys(classNames); | ||||
|  | ||||
|   // updates the DOM and optionally saves the new theme to local storage | ||||
|   const changeTheme = useCallback( | ||||
|     (theme: string, updateStorage: boolean) => { | ||||
|     (theme: string, updateStorage?: boolean) => { | ||||
|       if (updateStorage) { | ||||
|         setPreferredTheme(theme); | ||||
|       } | ||||
|  | ||||
|       // remove all theme classes first to start fresh | ||||
|       const all = Object.values(classNames); | ||||
|       const d = document.documentElement; | ||||
|       d.classList.remove(...all); | ||||
|       d.classList.add(classNames[theme]); | ||||
|       document.documentElement.classList.remove(...all); | ||||
|       document.documentElement.classList.add(classNames[theme]); | ||||
|     }, | ||||
|     [classNames, setPreferredTheme] | ||||
|   ); | ||||
|  | ||||
|   // memoize browser media query handler | ||||
|   const handleMediaQuery = useCallback( | ||||
|     (e?: MediaQueryList) => { | ||||
|     (e: MediaQueryListEvent | MediaQueryList) => { | ||||
|       // get the user's preferred theme via their OS/browser settings | ||||
|       const media = e || window.matchMedia(darkModeQuery); | ||||
|       const systemTheme = media.matches ? "dark" : "light"; | ||||
|       const systemTheme = e.matches ? "dark" : "light"; | ||||
|  | ||||
|       // keep track of the resolved theme whether or not we change it below | ||||
|       setResolvedTheme(systemTheme); | ||||
|  | ||||
|       // only actually change the theme if preference is unset (and *don't* save new theme to storage) | ||||
|       if (!preferredTheme || !validThemes.includes(preferredTheme)) changeTheme(systemTheme, false); | ||||
|       if (!preferredTheme || !themeNames.includes(preferredTheme)) { | ||||
|         changeTheme(systemTheme, false); | ||||
|       } | ||||
|     }, | ||||
|     [changeTheme, preferredTheme, validThemes] | ||||
|     [changeTheme, preferredTheme, themeNames] | ||||
|   ); | ||||
|   // ref hack to avoid adding handleMediaQuery as a dependency | ||||
|   const mediaListener = useRef(handleMediaQuery); | ||||
|   mediaListener.current = handleMediaQuery; | ||||
|  | ||||
|   // listen for changes in OS preference | ||||
|   useEffect(() => { | ||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
|     const handler = (...args: any) => mediaListener.current(...args); | ||||
|     const media = window.matchMedia(darkModeQuery); | ||||
|  | ||||
|     media.addEventListener("change", handler); | ||||
|     handler(media); | ||||
|     media.addEventListener("change", handleMediaQuery); | ||||
|     handleMediaQuery(media); | ||||
|  | ||||
|     // clean up the event listener | ||||
|     return () => { | ||||
|       media.removeEventListener("change", handler); | ||||
|       media.removeEventListener("change", handleMediaQuery); | ||||
|     }; | ||||
|   }, []); | ||||
|   }, [handleMediaQuery]); | ||||
|  | ||||
|   // color-scheme handling (tells browser how to render built-in elements like forms, scrollbars, etc.) | ||||
|   useEffect(() => { | ||||
|     // only "light" and "dark" are valid here | ||||
|     const colorScheme = ["light", "dark"].includes(preferredTheme) ? preferredTheme : resolvedTheme; | ||||
|  | ||||
|     document.documentElement.style.setProperty("color-scheme", colorScheme); | ||||
|     document.documentElement.style?.setProperty("color-scheme", colorScheme); | ||||
|   }, [preferredTheme, resolvedTheme]); | ||||
|  | ||||
|   return ( | ||||
| @@ -101,8 +96,8 @@ export const ThemeProvider = ({ | ||||
|           }, | ||||
|           [changeTheme] | ||||
|         ), | ||||
|         preferredTheme: validThemes.includes(preferredTheme) ? preferredTheme : undefined, | ||||
|         resolvedTheme: validThemes.includes(preferredTheme) ? preferredTheme : resolvedTheme, | ||||
|         preferredTheme: themeNames.includes(preferredTheme) ? preferredTheme : undefined, | ||||
|         resolvedTheme: themeNames.includes(preferredTheme) ? preferredTheme : resolvedTheme, | ||||
|       }} | ||||
|     > | ||||
|       {children} | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import type { NoteType } from "../../types"; | ||||
| export const getNoteSlugs = async () => { | ||||
|   // get all files in NOTES_DIR | ||||
|   const files = await fs.readdir(path.join(process.cwd(), NOTES_DIR)); | ||||
|  | ||||
|   // narrow to only the .mdx files and strip the .mdx extension | ||||
|   return files.filter((file) => /\.mdx$/.test(file)).map((noteFile) => noteFile.replace(/\.mdx$/, "")); | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user