feat(frontend): split theme CSS vars into a standalone theme.css
Phase 1 of stylix integration (#1457): extract the Catppuccin palette into a dedicated, separately-linked stylesheet so a theme swap can replace just that file without rebuilding the rest of the frontend. - shared/src/theme.css (new): the `:root` palette, moved out of base.css (which now holds only the body typography it references). - shared/package.json: export `./theme.css`. - dashboard/src/theme.css + agent/src/theme.css (new): one-line re-exports of @hive/shared/theme.css so each package's esbuild emits its own standalone `dist/static/theme.css` (palette is NOT inlined into the page bundles). - both build.mjs: add theme.css to the CSS build list. - every page (dashboard index/flow/logs, agent index/stats/screen): link `theme.css` first, ahead of the page CSS, so the `:root` vars resolve for everything. - docs/web-ui/css-vars.md: document the split + the no-rebuild rationale. Behaviour-neutral — same colours, just relocated. Verified both `npm run build` outputs: theme.css emits standalone (383b) with the palette; no `--*` palette defs duplicated into common.css/agent.css. Phase 2 (nix derivation that swaps theme.css from stylix colours) is a follow-up; touches nix/frontend.nix, coordinating with damocles. Part of #1457.
This commit is contained in:
parent
a3e6585266
commit
e70584b632
14 changed files with 88 additions and 38 deletions
|
|
@ -1,11 +1,22 @@
|
||||||
# CSS custom properties (theme variables)
|
# CSS custom properties (theme variables)
|
||||||
|
|
||||||
All colour variables are declared **once** in
|
All colour variables are declared **once** in
|
||||||
`frontend/packages/shared/src/base.css` under `:root`.
|
`frontend/packages/shared/src/theme.css` under `:root`.
|
||||||
Per-page stylesheets (`common.css`, `dashboard.css`, `flow.css`, `logs.css`, `agent.css`) must reference these
|
Per-page stylesheets (`common.css`, `dashboard.css`, `flow.css`, `logs.css`, `agent.css`) must reference these
|
||||||
names and must **not** redeclare them.
|
names and must **not** redeclare them. (`base.css` holds only the
|
||||||
|
shared `body` typography — it references the palette but no longer
|
||||||
|
defines it.)
|
||||||
|
|
||||||
## Palette (`base.css`)
|
`theme.css` is deliberately a **standalone** stylesheet, not `@import`ed
|
||||||
|
into the page bundles: each package re-exports it (`src/theme.css` →
|
||||||
|
`@import "@hive/shared/theme.css"`) so esbuild emits its own
|
||||||
|
`dist/static/theme.css`, and every page links it **first**
|
||||||
|
(`<link rel="stylesheet" href=".../theme.css">`) ahead of the page CSS.
|
||||||
|
Because the palette lives in its own output file, a theme swap — e.g. a
|
||||||
|
stylix-generated variant carrying the same variable names — can replace
|
||||||
|
just that one file without rebuilding the rest of the frontend bundle.
|
||||||
|
|
||||||
|
## Palette (`theme.css`)
|
||||||
|
|
||||||
| Variable | Hex | Catppuccin Mocha | Use |
|
| Variable | Hex | Catppuccin Mocha | Use |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,19 @@ await build({
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bundle the CSS — the @import lines pull in shared/base.css and
|
// Bundle the CSS. `theme.css` re-exports the standalone Catppuccin
|
||||||
// shared/terminal.css from the @hive/shared workspace dep.
|
// palette (kept its own output file so a theme swap replaces only it,
|
||||||
await build({
|
// no bundle rebuild); `agent.css`'s @import lines pull in shared
|
||||||
entryPoints: [src('agent.css')],
|
// base.css + terminal.css from the @hive/shared workspace dep.
|
||||||
outfile: staticDir('agent.css'),
|
for (const entry of ['theme.css', 'agent.css']) {
|
||||||
bundle: true,
|
await build({
|
||||||
loader: { '.css': 'css' },
|
entryPoints: [src(entry)],
|
||||||
logLevel: 'info',
|
outfile: staticDir(entry),
|
||||||
});
|
bundle: true,
|
||||||
|
loader: { '.css': 'css' },
|
||||||
|
logLevel: 'info',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const html of ['index.html', 'stats.html', 'screen.html']) {
|
for (const html of ['index.html', 'stats.html', 'screen.html']) {
|
||||||
copyFileSync(src(html), dist(html));
|
copyFileSync(src(html), dist(html));
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>hyperhive agent</title>
|
<title>hyperhive agent</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="icon">
|
<link rel="icon" type="image/svg+xml" href="icon">
|
||||||
|
<link rel="stylesheet" href="static/theme.css">
|
||||||
<link rel="stylesheet" href="static/agent.css">
|
<link rel="stylesheet" href="static/agent.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="agent-shell">
|
<body class="agent-shell">
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>screen</title>
|
<title>screen</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="icon">
|
<link rel="icon" type="image/svg+xml" href="icon">
|
||||||
|
<link rel="stylesheet" href="static/theme.css">
|
||||||
<link rel="stylesheet" href="static/agent.css">
|
<link rel="stylesheet" href="static/agent.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="screen-shell">
|
<body class="screen-shell">
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>hyperhive agent — stats</title>
|
<title>hyperhive agent — stats</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="icon">
|
<link rel="icon" type="image/svg+xml" href="icon">
|
||||||
|
<link rel="stylesheet" href="static/theme.css">
|
||||||
<link rel="stylesheet" href="static/agent.css">
|
<link rel="stylesheet" href="static/agent.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
6
frontend/packages/agent/src/theme.css
Normal file
6
frontend/packages/agent/src/theme.css
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/* Standalone theme bundle — re-exports the shared Catppuccin palette so
|
||||||
|
esbuild emits it as its own `dist/static/theme.css`, linked first by
|
||||||
|
every agent page. Kept separate from the page bundles so a theme swap
|
||||||
|
(e.g. stylix) replaces only this file. See @hive/shared/theme.css +
|
||||||
|
docs/web-ui/css-vars.md. */
|
||||||
|
@import "@hive/shared/theme.css";
|
||||||
|
|
@ -77,10 +77,11 @@ await build({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bundle CSS — one entry per page. esbuild resolves @import including
|
// Bundle CSS — one entry per page. esbuild resolves @import including
|
||||||
// the package re-exports from @hive/shared. Each page loads common.css
|
// the package re-exports from @hive/shared. Each page loads theme.css
|
||||||
// (shared typography, badges, buttons, inbox, side panel) plus its own
|
// (the standalone Catppuccin palette — kept its own file so a theme
|
||||||
// page-specific bundle.
|
// swap replaces only it) + common.css (shared typography, badges,
|
||||||
for (const entry of ['common.css', 'dashboard.css', 'flow.css', 'logs.css']) {
|
// buttons, inbox, side panel) plus its own page-specific bundle.
|
||||||
|
for (const entry of ['theme.css', 'common.css', 'dashboard.css', 'flow.css', 'logs.css']) {
|
||||||
await build({
|
await build({
|
||||||
entryPoints: [src(entry)],
|
entryPoints: [src(entry)],
|
||||||
outfile: staticDir(entry),
|
outfile: staticDir(entry),
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>hyperhive // FL0W</title>
|
<title>hyperhive // FL0W</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<link rel="stylesheet" href="/static/theme.css">
|
||||||
<link rel="stylesheet" href="/static/common.css">
|
<link rel="stylesheet" href="/static/common.css">
|
||||||
<link rel="stylesheet" href="/static/flow.css">
|
<link rel="stylesheet" href="/static/flow.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>hyperhive // h1ve-c0re</title>
|
<title>hyperhive // h1ve-c0re</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<link rel="stylesheet" href="/static/theme.css">
|
||||||
<link rel="stylesheet" href="/static/common.css">
|
<link rel="stylesheet" href="/static/common.css">
|
||||||
<link rel="stylesheet" href="/static/dashboard.css">
|
<link rel="stylesheet" href="/static/dashboard.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>hyperhive // LOGS</title>
|
<title>hyperhive // LOGS</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<link rel="stylesheet" href="/static/theme.css">
|
||||||
<link rel="stylesheet" href="/static/common.css">
|
<link rel="stylesheet" href="/static/common.css">
|
||||||
<link rel="stylesheet" href="/static/logs.css">
|
<link rel="stylesheet" href="/static/logs.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
6
frontend/packages/dashboard/src/theme.css
Normal file
6
frontend/packages/dashboard/src/theme.css
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/* Standalone theme bundle — re-exports the shared Catppuccin palette so
|
||||||
|
esbuild emits it as its own `dist/static/theme.css`, linked first by
|
||||||
|
every dashboard page. Kept separate from the page bundles so a theme
|
||||||
|
swap (e.g. stylix) replaces only this file. See @hive/shared/theme.css
|
||||||
|
+ docs/web-ui/css-vars.md. */
|
||||||
|
@import "@hive/shared/theme.css";
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.js",
|
".": "./src/index.js",
|
||||||
"./terminal.js": "./src/terminal.js",
|
"./terminal.js": "./src/terminal.js",
|
||||||
|
"./theme.css": "./src/theme.css",
|
||||||
"./base.css": "./src/base.css",
|
"./base.css": "./src/base.css",
|
||||||
"./terminal.css": "./src/terminal.css"
|
"./terminal.css": "./src/terminal.css"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,10 @@
|
||||||
/* Base palette + typography shared by the hive-c0re dashboard and the
|
/* Base typography shared by the hive-c0re dashboard and the hive-ag3nt
|
||||||
hive-ag3nt web UI. Catppuccin Mocha. Per-page stylesheets append on
|
web UI. The colour variables it references (`--bg`, `--fg`, …) live in
|
||||||
top of this and must NOT redeclare the colour variables — the whole
|
the standalone `theme.css` (Catppuccin Mocha), linked separately by
|
||||||
point of pulling them out is one source of truth. */
|
every page BEFORE this file so the `:root` vars resolve — see
|
||||||
:root {
|
`theme.css` + docs/web-ui/css-vars.md. Per-page stylesheets append on
|
||||||
--bg: #1e1e2e; /* base */
|
top of this and must NOT redeclare the colour variables; `theme.css`
|
||||||
--bg-elev: #181825; /* mantle */
|
is the one source of truth. */
|
||||||
--crust: #11111b; /* crust — terminal background */
|
|
||||||
--fg: #cdd6f4; /* text */
|
|
||||||
--muted: #7f849c; /* overlay1 */
|
|
||||||
--purple: #cba6f7; /* mauve */
|
|
||||||
--purple-dim: #45475a;/* surface1 */
|
|
||||||
--cyan: #89dceb; /* sky */
|
|
||||||
--blue: #89b4fa; /* blue */
|
|
||||||
--pink: #f5c2e7; /* pink */
|
|
||||||
--amber: #fab387; /* peach */
|
|
||||||
--yellow: #f9e2af; /* yellow */
|
|
||||||
--green: #a6e3a1; /* green */
|
|
||||||
--red: #f38ba8; /* red */
|
|
||||||
--border: #313244; /* surface0 */
|
|
||||||
--subtext0: #a6adc8; /* subtext0 — secondary/toolbar text, dimmer than --fg but lighter than --muted */
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|
|
||||||
30
frontend/packages/shared/src/theme.css
Normal file
30
frontend/packages/shared/src/theme.css
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Theme colour variables (Catppuccin Mocha) — the single source of
|
||||||
|
truth for the hive UI palette. Kept in a standalone file, linked as
|
||||||
|
its own `<link rel="stylesheet" href=".../theme.css">` by every page
|
||||||
|
BEFORE the page CSS, so the `:root` vars are defined for everything
|
||||||
|
that references them (base typography, terminal, dashboard, agent).
|
||||||
|
|
||||||
|
Why standalone rather than `@import`ed into the page bundles: esbuild
|
||||||
|
inlines `@import` at build time, which would bake the palette into
|
||||||
|
every CSS bundle. Emitting `theme.css` as its own output file lets a
|
||||||
|
theme swap (e.g. a stylix-generated variant carrying the same var
|
||||||
|
names) replace just this one file without rebuilding the rest of the
|
||||||
|
frontend. See docs/web-ui/css-vars.md. */
|
||||||
|
:root {
|
||||||
|
--bg: #1e1e2e; /* base */
|
||||||
|
--bg-elev: #181825; /* mantle */
|
||||||
|
--crust: #11111b; /* crust — terminal background */
|
||||||
|
--fg: #cdd6f4; /* text */
|
||||||
|
--muted: #7f849c; /* overlay1 */
|
||||||
|
--purple: #cba6f7; /* mauve */
|
||||||
|
--purple-dim: #45475a;/* surface1 */
|
||||||
|
--cyan: #89dceb; /* sky */
|
||||||
|
--blue: #89b4fa; /* blue */
|
||||||
|
--pink: #f5c2e7; /* pink */
|
||||||
|
--amber: #fab387; /* peach */
|
||||||
|
--yellow: #f9e2af; /* yellow */
|
||||||
|
--green: #a6e3a1; /* green */
|
||||||
|
--red: #f38ba8; /* red */
|
||||||
|
--border: #313244; /* surface0 */
|
||||||
|
--subtext0: #a6adc8; /* subtext0 — secondary/toolbar text, dimmer than --fg but lighter than --muted */
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue