You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
importReact,{useContext,useState}from"react";// utilsexportfunctioncookieToObj(cookie: string|undefined): Record<string,string>{if(cookie){returncookie.split("; ").reduce((obj: Record<string,string>,pair)=>{const[k,v]=pair.split("=");obj[k]=v;returnobj;},{});}return{};}// typesexporttypeResolvedTheme="light"|"dark";exporttypeUnResolvedTheme=ResolvedTheme|"system";exportinterfaceUseTheme{unResolvedTheme: UnResolvedTheme;resolvedTheme: ResolvedTheme;setTheme: (theme: UnResolvedTheme)=>void;nextTheme: ()=>UnResolvedTheme;}// constantsconstTHEME_KEY="x-theme";// for local storage and cookieconstDEFAULT_RESOLVED_THEME="dark";exportconstTHEMES: ("light"|"dark"|"system")[]=["system","light","dark"];constThemeContext=React.createContext<UseTheme>({resolvedTheme: DEFAULT_RESOLVED_THEME,unResolvedTheme: DEFAULT_RESOLVED_THEME,setTheme: ()=>{},nextTheme: ()=>DEFAULT_RESOLVED_THEME,});// functions to exportexportdefaultfunctionThemeProvider({
children,
cookies,
defaultTheme =undefined,}: {children: React.ReactNode;cookies: string|undefined;defaultTheme?: UnResolvedTheme;}){// cookies theme > local storage theme > provided default theme > builtin default themeconstinitialTheme=getCookiesTheme(cookies)||getLocalStorageTheme()||defaultTheme||DEFAULT_RESOLVED_THEME;constsystemTheme=useSystemTheme();const[unResolvedTheme,setUnResolvedTheme]=useState<UnResolvedTheme>(initialTheme);const[resolvedTheme,setResolvedTheme]=useState<ResolvedTheme>(()=>resolve(unResolvedTheme,systemTheme),);useEffect(()=>{if(unResolvedTheme==="system"){setResolvedTheme(systemTheme);}else{setResolvedTheme(resolve(unResolvedTheme,systemTheme));}},[systemTheme,unResolvedTheme]);useEffect(()=>{if(typeofdocument!=='undefined'){constbodyClassList=document.querySelector("body")?.classList;THEMES.forEach(theme=>bodyClassList?.remove(theme));// remove old themedocument.querySelector("body")?.classList.add(resolvedTheme);// add new theme}},[resolvedTheme])constsetTheme=(newTheme: UnResolvedTheme)=>{setUnResolvedTheme(newTheme);setClientSideCookieTheme(newTheme);// we need cookie so that server can prerender correct page to avoid flashingsetLocalStorageTheme(newTheme);// we need local storage to persistent cookie long term, but it does not get send to server};constnextTheme=()=>THEMES[(THEMES.indexOf(unResolvedTheme)+1)%THEMES.length];return(<ThemeContext.Providervalue={{ resolvedTheme, unResolvedTheme, setTheme, nextTheme }}>{children}</ThemeContext.Provider>);}// convinent hook to check the current theme / change the themeexportfunctionuseTheme(): UseTheme{returnuseContext(ThemeContext);}// internal methods, for implementationfunctionresolve(unResolvedTheme: UnResolvedTheme,systemTheme: ResolvedTheme){returnunResolvedTheme==="system" ? systemTheme : unResolvedTheme;}functionuseSystemTheme(): ResolvedTheme{const[systemTheme,setSystemTheme]=useState<ResolvedTheme>(getSystemTheme);// listen for system changes, so that page react when user system theme changesuseEffectOnce(()=>{consthandleEvent=(event: MediaQueryListEvent)=>{constnewTheme=event.matches ? "light" : "dark";console.log(`MediaQueryListEvent=${event}`);setSystemTheme(newTheme);};if(typeofwindow!=="undefined"&&window.matchMedia){window.matchMedia("(prefers-color-scheme: light)").addEventListener("change",handleEvent);return()=>window.matchMedia("(prefers-color-scheme: light)").removeEventListener("change",handleEvent);}});returnsystemTheme;}functiongetCookiesTheme(cookies: string|undefined): Nullable<UnResolvedTheme>{returncookieToObj(cookies)[THEME_KEY]asNullable<UnResolvedTheme>;}functionsetClientSideCookieTheme(theme: UnResolvedTheme,days=0){if(typeofdocument!=="undefined"&&theme){constcookieObj=cookieToObj(document.cookie);cookieObj[THEME_KEY]=theme;if(days){vardate=newDate();date.setTime(date.getTime()+days*24*60*60*1000);document.cookie=`expires=${date.toUTCString()}`;}document.cookie=`${THEME_KEY}=${theme}`;}}functiongetSystemTheme(): ResolvedTheme{if(typeofwindow!=="undefined"&&window.matchMedia){if(window.matchMedia("(prefers-color-scheme: light)").matches){return"light";}elseif(window.matchMedia("(prefers-color-scheme: dark)").matches){return"dark";}}returnDEFAULT_RESOLVED_THEME;}functionsetLocalStorageTheme(theme: UnResolvedTheme){if(typeoflocalStorage!=="undefined"){localStorage.setItem(THEME_KEY,theme);}}functiongetLocalStorageTheme(): Nullable<UnResolvedTheme>{if(typeoflocalStorage!=="undefined"){consttheme=localStorage.getItem(THEME_KEY);if(theme!==null){returnthemeasUnResolvedTheme;}}returnundefined;}functionremoveClientSideCookieTheme(){if(typeofdocument!=="undefined"){constcookieObj=cookieToObj(document.cookie);deletecookieObj[THEME_KEY];}}functionremoveLocalStorageTheme(): void{if(typeoflocalStorage!=="undefined"){localStorage.removeItem(THEME_KEY);}}
// ... your other code// https://nextjs.org/docs/api-reference/data-fetching/get-server-side-propsexportfunctiongetServerSideProps({ req }: {req: IncomingMessage}){// set the cookie such that we can pre-render page with correct themereturn{props: {cookies: req?.headers?.cookie},};}