another step

This commit is contained in:
hamid
2026-06-18 01:42:14 +03:30
parent e135b0b919
commit 6294cb4248
14 changed files with 70 additions and 101 deletions
-52
View File
@@ -1,52 +0,0 @@
import { COOKIE_NAMES } from '@/lib/cookies';
/**
* Inline synchronous script placed in <head> — runs before any paint.
*
* Two jobs:
* 1. Set data-mui-color-scheme on <html> from our cookie, so the server-set
* attribute and the first-paint attribute always agree (no flash).
* 2. Patch Storage.prototype so MUI v9's internal localStorage reads for key
* 'mode' return null (forcing MUI to use the defaultMode prop we derive
* from the cookie on the server) and writes to 'mode' are routed to our
* cookie instead of localStorage.
*
* Why patch Storage.prototype instead of storageWindow={null}?
* In MUI v9 localStorageManager: `if (!storageWindow && typeof window !== 'undefined') {
* storageWindow = window; }` — null is falsy, so storageWindow={null} is silently
* overridden to window in the browser. The prototype patch is the only reliable way.
*/
export function ColorSchemeScript() {
const cookieName = COOKIE_NAMES.COLOR_SCHEME; // 'color-scheme'
const maxAge = 60 * 60 * 24 * 365;
// MUI v9 default modeStorageKey (InitColorSchemeScript.mjs: DEFAULT_MODE_STORAGE_KEY = 'mode')
const muiModeKey = 'mode';
const script =
`(function(){` +
// ── 1. Set attribute from cookie before first paint ─────────────────────
`var m=document.cookie.match(/(^|;)\\s*${cookieName}=([^;]*)/);` +
`var s=m?decodeURIComponent(m[2]):(window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light');` +
`document.documentElement.setAttribute('data-mui-color-scheme',s==='dark'?'dark':'light');` +
// ── 2. Intercept Storage so MUI never touches localStorage ───────────────
`try{` +
`var _s=Storage.prototype.setItem,_g=Storage.prototype.getItem,_r=Storage.prototype.removeItem;` +
`Storage.prototype.setItem=function(k,v){` +
`if(this===window.localStorage&&k==='${muiModeKey}'){` +
`if(v==='dark'||v==='light')document.cookie='${cookieName}='+v+';path=/;max-age=${maxAge};samesite=lax';` +
`else document.cookie='${cookieName}=;path=/;max-age=0';` +
`return;}` +
`_s.call(this,k,v);};` +
`Storage.prototype.getItem=function(k){` +
`if(this===window.localStorage&&k==='${muiModeKey}')return null;` +
`return _g.call(this,k);};` +
`Storage.prototype.removeItem=function(k){` +
`if(this===window.localStorage&&k==='${muiModeKey}'){` +
`document.cookie='${cookieName}=;path=/;max-age=0';return;}` +
`_r.call(this,k);};` +
`}catch(e){}` +
`})();`;
// eslint-disable-next-line react/no-danger
return <script dangerouslySetInnerHTML={{ __html: script }} />;
}
+1 -2
View File
@@ -3,7 +3,7 @@ import { LIGHT_THEME } from './light';
import { DARK_THEME } from './dark';
import APP_THEME, { APP_THEME_LTR, APP_THEME_RTL } from './theme';
import { getDirection } from './direction';
import { ColorSchemeScript } from './ColorSchemeScript';
export {
APP_THEME,
@@ -14,5 +14,4 @@ export {
LIGHT_THEME as default,
AppThemeProvider as ThemeProvider,
getDirection,
ColorSchemeScript,
};