fix(dashboard): inline improvement modal script via readFileSync in config

Observable Framework proxies all src/*.js files through its own bundler —
<script type="module"> imports from <head> resolve to circular re-export
shims and never execute. The fix: read improvement-modal.js at config load
time in Node.js, strip the ES module export keyword, and interpolate the
content as a plain <script> block in the head config. It runs on every page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 00:32:54 +01:00
parent f3568cb111
commit 71488729a1

View File

@@ -1,3 +1,18 @@
import {readFileSync} from "node:fs";
import {fileURLToPath} from "node:url";
import {dirname, join} from "node:path";
// Read improvement-modal.js at config load time and inject as a plain <script>.
// Observable Framework proxies all src/*.js files through its own module
// bundler — they cannot be imported via a raw <script type="module"> in <head>.
// Reading the file here and stripping the ES module export is the reliable path.
const _configDir = dirname(fileURLToPath(import.meta.url));
const _modalScript = readFileSync(
join(_configDir, "src/components/improvement-modal.js"), "utf-8"
)
.replace(/^export function /gm, "function ") // strip ES module export
+ "\ninitImprovementModal();\n"; // auto-initialise
export default {
root: "src",
title: "Custodian State Hub",
@@ -75,10 +90,7 @@ export default {
],
theme: ["air", "near-midnight"],
head: `<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🗄️</text></svg>">
<script type="module">
import {initImprovementModal} from "/components/improvement-modal.js";
initImprovementModal({apiBase: "http://127.0.0.1:8000", domain: "custodian"});
</script>
<script>${_modalScript}</script>
<style>
.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; }
.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; padding-right: 1.6rem; }