feat(renderer): toggle <link disabled> on theme-changed instead of page reload

Replace the page-reload IPC handling in the theme-changed listener with an
in-place toggle of the preloaded <link id="theme-*"> tags. The helper scans
for a matching link first and only mutates disabled states when one exists,
so an unknown id (or main-process miss) short-circuits and preserves the
currently active theme. body.className is always set to the requested id so
legacy selectors keep matching.

Add tests/theme-renderer-apply.test.js with three cases covering: switching
to a fresh theme, idempotent re-switch, and the unknown-id short-circuit.
The test's local helper mirrors the renderer implementation so future drift
is caught at test time.

Amit Haridas
This commit is contained in:
2026-09-14 20:11:44 +05:30
parent ceeda453be
commit 0bc50c7d54
2 changed files with 114 additions and 1 deletions
+28 -1
View File
@@ -3002,8 +3002,35 @@ ipcRenderer.on('toggle-find', () => {
document.getElementById('find-input').focus();
}
});
/**
* Switch the active theme by toggling the `disabled` attribute on the
* preloaded `<link id="theme-<id>">` tags injected by src/index.html.
* Preloading all themes at startup avoids a network roundtrip on every
* switch; toggling `disabled` is a sub-millisecond DOM mutation that the
* browser applies on the next style-recalc. We keep `body.className` set
* to `theme-<id>` so any legacy rule (and the `_base.css`-style helpers)
* that depend on the body class still match.
*/
function applyThemeByLinkToggle(id) {
const all = document.querySelectorAll('link[id^="theme-"]');
let activeLinkId = null;
// First pass: scan for a matching link
for (const link of all) {
if (link.id === `theme-${id}`) activeLinkId = link.id;
}
if (activeLinkId !== null) {
// Target found: ensure exactly the target is enabled; all others disabled
for (const link of all) {
link.disabled = link.id !== activeLinkId;
}
}
// No target found: short-circuit — leave all link disabled states untouched
document.body.className = `theme-${id}`;
return activeLinkId;
}
ipcRenderer.on('theme-changed', (event, theme) => {
document.body.className = `theme-${theme}`;
applyThemeByLinkToggle(theme);
// After theme is applied, wait for next frame then signal renderer is ready
// This ensures complete UI initialization before files are opened