mara: 'wait the common styles is literally just the button stuff? pls make a button component now as part of this pr and replace the usage in the modal. replacing all usages and finally removing the btn styles from common css is a follow up then.' <hive-btn> (hive-btn.js) is a customized built-in <button is="hive-btn"> with its own shadow root -- extending HTMLButtonElement keeps every native button behaviour (click/keyboard activation, :disabled, form participation) instead of re-implementing it on a generic wrapper. Shadow root holds only an adopted stylesheet + a <slot>, so the button's light-DOM content (label, or asyncBtn's swapped-in spinner span) renders through unchanged -- slotted content stays styled by the light-DOM cascade, so the global .spinner class still applies. Variants (cancel/confirm/danger) are a 'variant' attribute, not a CSS class, since they're a semantic prop of the component. Customized built-ins aren't supported in Safari/WebKit -- fine here, the project targets recent Firefox only (same reasoning as the original custom-elements pilot). Wired into modal.js: HiveDialog's buttons now render as <button is="hive-btn" variant="...">, replacing the old component-common.css .btn copy -- deleted that file + component- styles.js entirely (their sole purpose was giving dialog buttons a .btn look, which hive-btn now owns properly). dom.js's el() gained support so it can create customized built-ins the same way it creates everything else. hive-dialog.css dropped the now-dead .cancel/.confirm/.confirm.danger rules. Per mara's scoping: NOT touching the other .btn consumers across the app (dashboard/agent submit buttons, form() helper, etc.) or removing .btn from dashboard/common.css / agent/agent.css in this PR -- that migration + cleanup is an explicit follow-up. Verified with a full frontend build (grepped bundled JS for hive-btn/ variant to confirm it inlines); nix fmt clean.
131 lines
6.8 KiB
JavaScript
131 lines
6.8 KiB
JavaScript
// esbuild build for @hive/dashboard. Output layout (`dist/`):
|
|
//
|
|
// dist/index.html H0M3 menu hub — served by the Rust
|
|
// router at GET / (the landing page)
|
|
// dist/dashboard.html the operator dashboard SPA — served
|
|
// at GET /dashboard.html
|
|
// dist/flow.html served at GET /flow.html
|
|
// dist/logs.html served at GET /logs.html (AGENT/SYSTEM/AUDIT)
|
|
// dist/core.html served at GET /core.html (C0R3: kept
|
|
// state / container load)
|
|
// dist/builds.html served at GET /builds.html (BU1LDS:
|
|
// rebuild queue / meta inputs / build logs)
|
|
// dist/credentials.html served at GET /credentials.html
|
|
// (CR3D3NTIALS: matrix + github accounts)
|
|
// dist/static/home.js index.html (H0M3) entry — menu tiles +
|
|
// matrix-tile gating + identity line
|
|
// dist/static/tabs.js dashboard.html entry — tab renderers +
|
|
// tab routing + refreshState
|
|
// dist/static/flow.js /flow.html entry — broker terminal +
|
|
// @-mention composer
|
|
// dist/static/logs.js /logs.html entry — agent/system/audit
|
|
// log viewer sub-tabs
|
|
// dist/static/builds.js /builds.html entry — rebuild queue,
|
|
// meta inputs, build log history
|
|
// dist/static/credentials.js /credentials.html entry — matrix +
|
|
// github account sub-tabs
|
|
// dist/static/{home,tabs,flow,logs,builds,credentials}.js.map source map
|
|
// siblings
|
|
// dist/static/common.css loaded by every page (@hive/shared
|
|
// imports + shared typography/badges/
|
|
// buttons/inbox/side-panel)
|
|
// dist/static/dashboard.css dashboard.html only (dashboard-specific)
|
|
// dist/static/flow.css /flow.html only (flow chrome + composer)
|
|
// dist/static/logs.css /logs.html only (log viewer sub-tabs)
|
|
// dist/static/builds.css /builds.html only (build lifecycle hub)
|
|
// dist/static/home.css index.html (H0M3) only (tile grid)
|
|
// dist/static/credentials.css /credentials.html only (matrix + github
|
|
// account forms)
|
|
//
|
|
// Each JS entry bundles `./common.js` (DOM helpers, Panel singleton,
|
|
// NOTIF, path linkification) independently — esbuild inlines the shared
|
|
// module into each bundle rather than emitting a shared chunk (no
|
|
// `splitting: true`). The Rust binary mounts `dist/` as a
|
|
// `tower_http::ServeDir` fallback (`append_index_html_on_directories`
|
|
// serves index.html at /); the layout above keeps every URL the HTML
|
|
// files reference reachable without rewriting paths in the HTML. The
|
|
// dashboard SPA lives at /dashboard.html (a plain file, not a /dashboard/
|
|
// prefix) so it never shadows the exact-match /dashboard/stream +
|
|
// /dashboard/history SSE routes registered before the ServeDir fallback.
|
|
|
|
import { build } from 'esbuild';
|
|
import { mkdirSync, copyFileSync, rmSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const src = (p) => resolve(here, 'src', p);
|
|
const dist = (p) => resolve(here, 'dist', p);
|
|
const staticDir = (p) => resolve(here, 'dist', 'static', p);
|
|
|
|
rmSync(dist(''), { recursive: true, force: true });
|
|
mkdirSync(staticDir(''), { recursive: true });
|
|
|
|
// Bundle the JS entries. ES-module output, browser target, no minify
|
|
// (line-aligned source aids debugging; minification belongs in a later
|
|
// 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'), src('core.js'), src('builds.js'), src('credentials.js')],
|
|
outdir: staticDir(''),
|
|
bundle: true,
|
|
format: 'esm',
|
|
platform: 'browser',
|
|
target: ['es2022'],
|
|
sourcemap: true,
|
|
logLevel: 'info',
|
|
// `@hive/shared/modal.js` and `hive-btn.js` import their shadow-DOM
|
|
// component CSS (hive-dialog.css, hive-toast.css, hive-btn.css) as raw
|
|
// text via a plain `import css from './foo.css'` — the `text` loader turns
|
|
// that into a string constant at bundle time instead of erroring on an
|
|
// unrecognised extension. None of these JS entries import a `.css`
|
|
// file any other way, so this doesn't collide with the separate
|
|
// page-stylesheet bundling below (`loader: { '.css': 'css' }`), which
|
|
// runs as its own esbuild invocation over different entry points.
|
|
loader: { '.css': 'text' },
|
|
});
|
|
|
|
// Stream-worker entry (#448). Lives in a separate bundle: SharedWorker
|
|
// scripts run in a different global (`self` is the worker scope, no
|
|
// `window`) so they can't be inlined into tabs.js / flow.js. Output is
|
|
// at `static/stream-worker.js`; common.js's `openStream` references
|
|
// `/static/stream-worker.js` as the SharedWorker URL. `format: 'iife'`
|
|
// matches the classic-script load (`new SharedWorker(url, name)` with
|
|
// no `{ type: 'module' }`); Firefox is the #448 target and module
|
|
// SharedWorker support there is patchy, so keeping the worker as a
|
|
// classic script + IIFE bundle is the compatible default. argus nit
|
|
// on #453: if a future contributor adds an `import` to this bundle,
|
|
// the IIFE format will surface it as a build error rather than
|
|
// silently shipping broken code.
|
|
await build({
|
|
entryPoints: [src('stream-worker.js')],
|
|
outdir: staticDir(''),
|
|
bundle: true,
|
|
format: 'iife',
|
|
platform: 'browser',
|
|
target: ['es2022'],
|
|
sourcemap: true,
|
|
logLevel: 'info',
|
|
});
|
|
|
|
// Bundle CSS — one entry per page. esbuild resolves @import including
|
|
// the package re-exports from @hive/shared. Each page loads colors.css
|
|
// (the standalone base16 palette — the theme swap contract, its own file
|
|
// 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', 'core.css', 'builds.css', 'credentials.css']) {
|
|
await build({
|
|
entryPoints: [src(entry)],
|
|
outfile: staticDir(entry),
|
|
bundle: true,
|
|
loader: { '.css': 'css' },
|
|
logLevel: 'info',
|
|
});
|
|
}
|
|
|
|
for (const html of ['index.html', 'dashboard.html', 'flow.html', 'logs.html', 'settings.html', 'stats.html', 'core.html', 'builds.html', 'credentials.html']) {
|
|
copyFileSync(src(html), dist(html));
|
|
}
|
|
|
|
console.log('dashboard build ok →', dist(''));
|