feat(dashboard): add standalone C0R3 page (system tab → its own page)

Carves the dashboard's SYST3M tab content out into a standalone page at
/core.html, reached from the H0M3 hub, with a createTabStrip sub-tab
strip (default = Rebuild Queue): rebuild queue, meta inputs, kept state,
container load. Same minimal-chrome standalone-page pattern as
/logs.html (← home back-link + sub-tab nav).

This is the additive first step: the new page is its own esbuild bundle
that cold-loads /api/state and subscribes to /dashboard/stream for the
same live rebuild_queue_changed / meta_inputs_changed / meta_update_running
/ tombstones_changed events the dashboard uses. The four section
renderers are ported from tabs.js; the dashboard's SYST3M tab is left in
place and untouched, so this PR cannot regress the existing dashboard.
Removing the now-duplicate SYST3M tab + de-duplicating the renderers
(into a shared module) + splitting the shared section CSS out of
dashboard.css is the deliberate follow-up.

core.css imports dashboard.css wholesale (transitional) so the ported
sections render identically; dashboard.css does not import common.css so
nothing double-loads. build.mjs gains core.js / core.css / core.html
entries; no Rust change (hive-c0re serves dist/ via ServeDir, and the
/dashboard/stream + /dashboard/history routes are registered ahead of
the fallback).

Page name "C0R3" is a placeholder pending the operator's pick — trivially
renamed (the /core.html URL + the C0R3 label).
This commit is contained in:
iris 2026-06-10 19:03:38 +02:00 committed by mara
commit be8d97ded7
5 changed files with 683 additions and 3 deletions

View file

@ -6,6 +6,9 @@
// at GET /dashboard.html
// dist/flow.html served at GET /flow.html
// dist/logs.html served at GET /logs.html
// dist/core.html served at GET /core.html (C0R3: rebuild
// queue / meta inputs / kept state /
// container load — the old SYST3M tab)
// dist/static/home.js index.html (H0M3) entry — menu tiles +
// matrix-tile gating + identity line
// dist/static/tabs.js dashboard.html entry — tab renderers +
@ -52,7 +55,7 @@ mkdirSync(staticDir(''), { recursive: true });
// follow-up once asset sizes warrant it). esbuild writes each entry
// to `static/<name>.js` based on the entryPoint basename.
await build({
entryPoints: [src('tabs.js'), src('flow.js'), src('logs.js'), src('home.js'), src('settings.js'), src('stats.js')],
entryPoints: [src('tabs.js'), src('flow.js'), src('logs.js'), src('home.js'), src('settings.js'), src('stats.js'), src('core.js')],
outdir: staticDir(''),
bundle: true,
format: 'esm',
@ -91,7 +94,7 @@ await build({
// so a swap replaces only it) + theme.css (the semantic derivation
// layer) + common.css (shared typography, badges, buttons, inbox, side
// panel) plus its own page-specific bundle.
for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', 'flow.css', 'logs.css', 'home.css', 'settings.css', 'stats.css']) {
for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', 'flow.css', 'logs.css', 'home.css', 'settings.css', 'stats.css', 'core.css']) {
await build({
entryPoints: [src(entry)],
outfile: staticDir(entry),
@ -101,7 +104,7 @@ for (const entry of ['colors.css', 'theme.css', 'common.css', 'dashboard.css', '
});
}
for (const html of ['index.html', 'dashboard.html', 'flow.html', 'logs.html', 'settings.html', 'stats.html']) {
for (const html of ['index.html', 'dashboard.html', 'flow.html', 'logs.html', 'settings.html', 'stats.html', 'core.html']) {
copyFileSync(src(html), dist(html));
}