feat(FN-4916): complete Step 1 — add static theme-data link
Fusion-Task-Id: FN-4916 Fusion-Task-Lineage: 80b56c97-04c6-4cd4-bb83-e3ef8faaa4ee
This commit is contained in:
committed by
gsxdsm
parent
03a10c7419
commit
e25f8b20aa
@@ -158,16 +158,10 @@ function applyThemeAttributes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load theme-data.css for non-default themes.
|
* Reconcile the statically declared #theme-data stylesheet href for the current base URI.
|
||||||
* Safely handles existing links by checking href and updating if stale.
|
|
||||||
* After href reconciliation, existing links are moved to the end of <head>
|
|
||||||
* to ensure color-theme CSS rules take precedence over base token
|
|
||||||
* redefinitions in subsequent stylesheets (CSS cascade correctness).
|
|
||||||
*
|
*
|
||||||
* This is critical for dark mode: if #theme-data is injected early by
|
* The link is authored in app/index.html so browsers can discover and fetch theme-data.css
|
||||||
* pre-hydration scripts but styles.css loads later and redefines base
|
* during HTML parsing. Runtime only updates href when needed (notably file:// Electron paths).
|
||||||
* tokens, those redefinitions win the cascade unless theme-data is
|
|
||||||
* repositioned to come after them.
|
|
||||||
*/
|
*/
|
||||||
function loadThemeDataStylesheet(): void {
|
function loadThemeDataStylesheet(): void {
|
||||||
if (!isBrowser) return;
|
if (!isBrowser) return;
|
||||||
@@ -176,22 +170,13 @@ function loadThemeDataStylesheet(): void {
|
|||||||
const existingLink = document.getElementById(THEME_DATA_ID) as HTMLLinkElement | null;
|
const existingLink = document.getElementById(THEME_DATA_ID) as HTMLLinkElement | null;
|
||||||
|
|
||||||
if (existingLink) {
|
if (existingLink) {
|
||||||
// Link exists - update href if it differs from expected (handles baseURI changes)
|
|
||||||
if (existingLink.href !== expectedHref) {
|
if (existingLink.href !== expectedHref) {
|
||||||
existingLink.href = expectedHref;
|
existingLink.href = expectedHref;
|
||||||
}
|
}
|
||||||
// Move existing link to end of <head> for CSS cascade correctness.
|
|
||||||
// This ensures color-theme rules (which use [data-color-theme="..."] selectors)
|
|
||||||
// are evaluated AFTER any subsequent stylesheets that might redefine base tokens.
|
|
||||||
// Without this, dark color themes can appear broken because base token
|
|
||||||
// redefinitions win the cascade over color-theme rules.
|
|
||||||
if (existingLink.parentNode === document.head && document.head.lastChild !== existingLink) {
|
|
||||||
document.head.appendChild(existingLink);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No existing link - create one
|
// Defensive fallback: index.html should always provide this link.
|
||||||
const link = document.createElement("link");
|
const link = document.createElement("link");
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
link.href = expectedHref;
|
link.href = expectedHref;
|
||||||
@@ -200,15 +185,10 @@ function loadThemeDataStylesheet(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unload theme-data.css when returning to default theme.
|
* No-op: #theme-data stays mounted permanently via static index.html markup.
|
||||||
|
* Theme rules only apply when [data-color-theme="..."] selectors match.
|
||||||
*/
|
*/
|
||||||
function unloadThemeDataStylesheet(): void {
|
function unloadThemeDataStylesheet(): void {}
|
||||||
if (!isBrowser) return;
|
|
||||||
const existing = document.getElementById(THEME_DATA_ID);
|
|
||||||
if (existing) {
|
|
||||||
existing.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook for theme management.
|
* Custom hook for theme management.
|
||||||
@@ -444,19 +424,8 @@ export function getThemeInitScript(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var existingLink = document.getElementById('theme-data');
|
var existingLink = document.getElementById('theme-data');
|
||||||
if (existingLink && existingLink.tagName === 'LINK') {
|
if (existingLink && existingLink.tagName === 'LINK' && existingLink.href !== themeDataUrl) {
|
||||||
if (existingLink.href !== themeDataUrl) {
|
existingLink.href = themeDataUrl;
|
||||||
existingLink.href = themeDataUrl;
|
|
||||||
}
|
|
||||||
if (existingLink.parentNode === document.head && document.head.lastChild !== existingLink) {
|
|
||||||
document.head.appendChild(existingLink);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var link = document.createElement('link');
|
|
||||||
link.rel = 'stylesheet';
|
|
||||||
link.href = themeDataUrl;
|
|
||||||
link.id = 'theme-data';
|
|
||||||
document.head.appendChild(link);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -38,8 +38,6 @@
|
|||||||
document.documentElement.setAttribute('data-theme', effectiveMode);
|
document.documentElement.setAttribute('data-theme', effectiveMode);
|
||||||
document.documentElement.setAttribute('data-color-theme', colorTheme);
|
document.documentElement.setAttribute('data-color-theme', colorTheme);
|
||||||
document.documentElement.style.fontSize = fontScale + '%';
|
document.documentElement.style.fontSize = fontScale + '%';
|
||||||
// Load theme-data.css for non-default themes to prevent flash
|
|
||||||
// This logic mirrors app/hooks/useTheme.ts#getThemeDataUrl()
|
|
||||||
if (colorTheme !== 'default') {
|
if (colorTheme !== 'default') {
|
||||||
var base = document.baseURI || (document.location && document.location.href) || '';
|
var base = document.baseURI || (document.location && document.location.href) || '';
|
||||||
var themeDataUrl;
|
var themeDataUrl;
|
||||||
@@ -48,33 +46,20 @@
|
|||||||
} else if (base.indexOf('http://') === 0 || base.indexOf('https://') === 0) {
|
} else if (base.indexOf('http://') === 0 || base.indexOf('https://') === 0) {
|
||||||
themeDataUrl = new URL('/theme-data.css', base).toString();
|
themeDataUrl = new URL('/theme-data.css', base).toString();
|
||||||
} else if (base.indexOf('file://') === 0) {
|
} else if (base.indexOf('file://') === 0) {
|
||||||
themeDataUrl = base.endsWith('/')
|
if (base.endsWith('/')) {
|
||||||
? base.slice(0, -1) + '/theme-data.css'
|
themeDataUrl = base.slice(0, -1) + '/theme-data.css';
|
||||||
: base.replace(/\/[^\/]+$/, '/theme-data.css');
|
} else {
|
||||||
|
var lastSlashIndex = base.lastIndexOf('/');
|
||||||
|
themeDataUrl = lastSlashIndex >= 0
|
||||||
|
? base.slice(0, lastSlashIndex) + '/theme-data.css'
|
||||||
|
: '/theme-data.css';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
themeDataUrl = '/theme-data.css';
|
themeDataUrl = '/theme-data.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for existing link and update href if stale
|
|
||||||
var existingLink = document.getElementById('theme-data');
|
var existingLink = document.getElementById('theme-data');
|
||||||
if (existingLink && existingLink.tagName === 'LINK') {
|
if (existingLink && existingLink.tagName === 'LINK' && existingLink.href !== themeDataUrl) {
|
||||||
// Update href if it differs (handles baseURI changes between loads)
|
existingLink.href = themeDataUrl;
|
||||||
if (existingLink.href !== themeDataUrl) {
|
|
||||||
existingLink.href = themeDataUrl;
|
|
||||||
}
|
|
||||||
// Move existing link to end of <head> for CSS cascade correctness.
|
|
||||||
// This ensures color-theme rules take precedence over base token
|
|
||||||
// redefinitions in subsequent stylesheets.
|
|
||||||
if (existingLink.parentNode === document.head && document.head.lastChild !== existingLink) {
|
|
||||||
document.head.appendChild(existingLink);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No existing link - create one
|
|
||||||
var link = document.createElement('link');
|
|
||||||
link.rel = 'stylesheet';
|
|
||||||
link.href = themeDataUrl;
|
|
||||||
link.id = 'theme-data';
|
|
||||||
document.head.appendChild(link);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -85,6 +70,7 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<!-- fusion:view-preload -->
|
<!-- fusion:view-preload -->
|
||||||
|
<link rel="stylesheet" href="/theme-data.css" id="theme-data" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user