mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-24 14:45:18 +00:00
fix(home): re-render after config loads to fix null homeCfg on direct load (#1194)
## Summary - On direct page load to `#/home` (or a full refresh), `renderHome()` runs before the async `/api/config/theme` fetch resolves, so `window.SITE_CONFIG` is `undefined` and `homeCfg` is `null` — showing SF defaults instead of the site's customisations. - When navigating from another page the fetch has already completed, which is why it works in that case. - Fix: subscribe to `theme-refresh` (the event fired ~300 ms after the config is fetched and applied) and re-render; clean up the listener in `destroy()`. This matches the existing pattern used by `analytics.js` and `map.js`. Fixes #1193 ## Test plan - [x] Hard-refresh directly to `#/home` — customised `heroTitle`, `heroSubtitle`, steps, footer links must render correctly - [x] Navigate from another page to Home — still renders correctly (no regression) - [x] Site with no custom config — defaults render, no JS errors - [x] Theme customiser changes while on Home page — page re-renders (theme-refresh re-render still works) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+9
-2
@@ -5,6 +5,7 @@
|
||||
let searchTimeout = null;
|
||||
let miniMap = null;
|
||||
let searchAbort = null; // AbortController for document-level listeners
|
||||
let _themeRefreshHandler = null;
|
||||
|
||||
const PREF_KEY = 'meshcore-user-level';
|
||||
const MY_NODES_KEY = 'meshcore-my-nodes'; // [{pubkey, name, addedAt}]
|
||||
@@ -31,9 +32,14 @@
|
||||
function init(container) {
|
||||
if (!localStorage.getItem(PREF_KEY)) {
|
||||
showChooser(container);
|
||||
return;
|
||||
} else {
|
||||
renderHome(container);
|
||||
}
|
||||
renderHome(container);
|
||||
_themeRefreshHandler = function() {
|
||||
if (!localStorage.getItem(PREF_KEY)) showChooser(container);
|
||||
else renderHome(container);
|
||||
};
|
||||
window.addEventListener('theme-refresh', _themeRefreshHandler);
|
||||
}
|
||||
|
||||
function showChooser(container) {
|
||||
@@ -237,6 +243,7 @@
|
||||
clearTimeout(searchTimeout);
|
||||
if (searchAbort) { searchAbort.abort(); searchAbort = null; }
|
||||
if (miniMap) { miniMap.remove(); miniMap = null; }
|
||||
if (_themeRefreshHandler) { window.removeEventListener('theme-refresh', _themeRefreshHandler); _themeRefreshHandler = null; }
|
||||
}
|
||||
|
||||
// ==================== MY NODES DASHBOARD ====================
|
||||
|
||||
@@ -126,7 +126,14 @@ async function effectiveBgFor(page, selector) {
|
||||
});
|
||||
|
||||
await step('Path link contrast (#pathsContent a) ≥ 4.5:1 in dark mode', async () => {
|
||||
const linkColor = await page.$eval('#pathsContent a[href^="#/nodes/"]', (el) => getComputedStyle(el).color);
|
||||
// Use page.evaluate (single CDP call) so querySelector and getComputedStyle
|
||||
// are atomic — page.$eval splits them across two calls, leaving a window
|
||||
// where a concurrent re-render can detach the element before getComputedStyle
|
||||
// runs, causing Chromium to return '' for color.
|
||||
const linkColor = await page.evaluate(() => {
|
||||
const el = document.querySelector('#pathsContent a[href^="#/nodes/"]');
|
||||
return el ? getComputedStyle(el).color : '';
|
||||
});
|
||||
const bgColor = await effectiveBgFor(page, '#pathsContent a[href^="#/nodes/"]');
|
||||
const fg = parseRgb(linkColor);
|
||||
const bg = parseRgb(bgColor);
|
||||
|
||||
Reference in New Issue
Block a user