diff --git a/src/context/App.tsx b/src/context/App.tsx index 50b6ee235ed2..5c8926b7d5b3 100644 --- a/src/context/App.tsx +++ b/src/context/App.tsx @@ -1,5 +1,14 @@ /* eslint-disable @typescript-eslint/no-empty-function */ -import React, { createContext, useContext, useEffect, useMemo, useState, useCallback, useRef } from 'react' +import React, { + createContext, + useContext, + useEffect, + useLayoutEffect, + useMemo, + useState, + useCallback, + useRef, +} from 'react' import { AppWindow } from './Window' import { WindowSearchUI } from 'components/SearchUI' import { navigate } from 'gatsby' @@ -1407,18 +1416,31 @@ export interface SiteSettings { const isLabel = (item: any) => !item?.url && item?.name +// The defaults the server renders with (no `window`, so no localStorage). The server always +// emits `
` and this settings shape, so +// the first client render must reproduce these exact values to match the SSR HTML during +// hydration. See `activeSiteSettings` below. +const SSR_DEFAULT_SITE_SETTINGS: SiteSettings = { + experience: 'posthog', + colorMode: 'light', + theme: 'light', + skinMode: 'modern', + cursor: 'default', + wallpaper: 'keyboard-garden', + clickBehavior: 'double', + performanceBoost: false, + screensaverDisabled: true, +} + +// useLayoutEffect warns during SSR; fall back to useEffect on the server where it's a no-op anyway. +const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect + const getInitialSiteSettings = (isMobile: boolean, compact: boolean) => { const lastReset = typeof window !== 'undefined' ? localStorage.getItem('lastReset') : null const siteSettings = { - experience: 'posthog', + ...SSR_DEFAULT_SITE_SETTINGS, colorMode: (typeof window !== 'undefined' && (window as any).__theme) || 'light', theme: (typeof window !== 'undefined' && (window as any).__theme) || 'light', - skinMode: 'modern', - cursor: 'default', - wallpaper: 'keyboard-garden', - clickBehavior: 'double', - performanceBoost: false, - screensaverDisabled: true, ...(typeof window !== 'undefined' ? JSON.parse(localStorage.getItem('siteSettings') || '{}') : {}), ...(!lastReset ? { experience: 'posthog' } : {}), } @@ -1441,7 +1463,19 @@ export const Provider = ({ children, element, location }: AppProviderProps) => { const taskbarRef = useRef