feat(ui): scaffold the codegraph ui viewer as a Svelte 5 + Vite workspace (CG-40)
Adds `ui/` as an npm workspace (Svelte 5.56 + Vite 7, devDependencies only — the engine's runtime dependencies are untouched) and chains its build into `npm run build`, so the browser viewer ships inside `dist/` with everything else: `build-bundle.sh` already copies `dist` wholesale and `pack-npm.sh` packs that bundle. Output is `dist/viewer/`, NOT `dist/ui/`: `src/ui/` is the engine's terminal ui (shimmer progress + its worker) and tsc compiles it to `dist/ui/`, so emitting there both deletes those modules — the CLI then dies at startup with `Cannot find module '../ui/shimmer-progress'` — and would leave the static server handing out compiled engine internals. The design spec is corrected to match. `scripts/check-ui-build.mjs` is the release guard: index.html must exist, be non-trivial, and every local asset it references must be on disk, and the compiled engine next door must still be intact. It runs after every UI build, again in `build-bundle.sh` once the bundle stage has copied `dist`, and again in `pack-npm.sh` once each archive is unpacked — so a broken viewer fails the release instead of shipping a CLI that serves a 404. `vite build` does not override an ambient NODE_ENV, so a shell or runner with NODE_ENV=development silently shipped dev-mode Svelte (~13 kB of dev-only runtime checks, warning in the user's console). The config now pins production for `command === 'build'`; macOS and Windows ARM64 then emit byte-identical bundle hashes. The shell itself follows docs/design/codegraph-ui-design-spec.md §2–§3.1: design tokens as CSS custom properties (light on bare `:root`, dark under both `prefers-color-scheme` and `[data-theme="dark"]`), square corners, hairline rules, one oxblood accent; top bar 48px / trail bar 34px / main; a hash router over `#/s/<id>`, `#/file/<path>`, with `#/map` and `#/flow` reserved for phase 2. Fonts are vendored through @fontsource rather than fetched, so a local reader works offline and never announces the project to a CDN. Verified: clean `npm run build` from an empty dist on macOS and on the Windows ARM64 VM (forward-slash asset URLs, CLI still starts, both assertion failure modes exit 1); `dist/viewer` present in a real darwin-arm64 bundle and in the packed npm platform package; shell geometry, tokens, all seven routes, both themes and font loading checked in headless Chromium with no console errors; `npm test` unaffected.
This commit is contained in:
+202
@@ -0,0 +1,202 @@
|
||||
/* =====================================================================
|
||||
codegraph ui — design tokens + global primitives
|
||||
|
||||
The engine's paper/ink editorial system (site/src/styles/theme.css),
|
||||
as specified in docs/design/codegraph-ui-design-spec.md §2: flat,
|
||||
hairline rules, square corners everywhere, no shadows, no gradients,
|
||||
sentence case, one oxblood accent, one amber (the "untested" badge).
|
||||
|
||||
Component-specific rules live in each .svelte file's scoped <style>.
|
||||
Only tokens, resets and cross-view primitives belong here.
|
||||
===================================================================== */
|
||||
|
||||
/* ---------- tokens: light / paper (the bare :root set) ---------- */
|
||||
:root {
|
||||
--paper: #f7f6f2;
|
||||
--paper-2: #f1efe8;
|
||||
--press: #e8e6dd;
|
||||
--press-2: #dedbd0;
|
||||
--ink: #16150f;
|
||||
--ink-2: #56544a;
|
||||
--ink-3: #87847a;
|
||||
--ink-4: #b4b1a5;
|
||||
--rule: #16150f;
|
||||
--rule-soft: #d6d3c8;
|
||||
--rule-faint: #e6e3d9;
|
||||
--accent: #7a2230;
|
||||
--accent-ink: #5e1a25;
|
||||
--accent-soft: #f0e3e5;
|
||||
--accent-line: #d9b3b9;
|
||||
--amber: #8a5a0b;
|
||||
--amber-soft: #f3e9d2;
|
||||
|
||||
--sans: 'Archivo Variable', 'Archivo', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
|
||||
--mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
||||
--code-size: 12.5px;
|
||||
--code-lh: 20px;
|
||||
|
||||
/* App-shell geometry, shared by the grid and by anything that has to
|
||||
offset itself under the bars (sticky rail headers, SVG overlays). */
|
||||
--topbar-h: 48px;
|
||||
--trailbar-h: 34px;
|
||||
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
/* ---------- tokens: dark / ink ----------
|
||||
Every colour is defined on the bare :root above; these blocks only
|
||||
redefine. `:not([data-theme="light"])` lets an explicit light choice
|
||||
win over the OS preference. */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme='light']) {
|
||||
--paper: #16150f;
|
||||
--paper-2: #1c1a14;
|
||||
--press: #23211a;
|
||||
--press-2: #2c2a22;
|
||||
--ink: #f3f1ea;
|
||||
--ink-2: #b8b5a8;
|
||||
--ink-3: #87847a;
|
||||
--ink-4: #5d5b52;
|
||||
--rule: #f3f1ea;
|
||||
--rule-soft: #34322a;
|
||||
--rule-faint: #26241d;
|
||||
--accent: #d48b96;
|
||||
--accent-ink: #e5a5ae;
|
||||
--accent-soft: #33201f;
|
||||
--accent-line: #6b3a42;
|
||||
--amber: #d9a94a;
|
||||
--amber-soft: #2e2716;
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] {
|
||||
--paper: #16150f;
|
||||
--paper-2: #1c1a14;
|
||||
--press: #23211a;
|
||||
--press-2: #2c2a22;
|
||||
--ink: #f3f1ea;
|
||||
--ink-2: #b8b5a8;
|
||||
--ink-3: #87847a;
|
||||
--ink-4: #5d5b52;
|
||||
--rule: #f3f1ea;
|
||||
--rule-soft: #34322a;
|
||||
--rule-faint: #26241d;
|
||||
--accent: #d48b96;
|
||||
--accent-ink: #e5a5ae;
|
||||
--accent-soft: #33201f;
|
||||
--accent-line: #6b3a42;
|
||||
--amber: #d9a94a;
|
||||
--amber-soft: #2e2716;
|
||||
}
|
||||
|
||||
/* ---------- reset ---------- */
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
/* body always paints --paper: the bars are transparent over it and a
|
||||
short view must not reveal the browser's own canvas colour. */
|
||||
background: var(--paper);
|
||||
color: var(--ink);
|
||||
font-family: var(--sans);
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
/* Square corners are non-negotiable in this system, including on the
|
||||
UA-styled controls (input, select, button) we do not restyle. */
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
background: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-weight: 600;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- app shell ----------
|
||||
Design spec §3.1: top bar 48px / trail bar 34px / main. The grid is on
|
||||
index.html's mount host, which App.svelte fills directly (no wrapper — a
|
||||
second #app would duplicate the id). */
|
||||
#app {
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: var(--topbar-h) var(--trailbar-h) 1fr;
|
||||
}
|
||||
|
||||
/* ---------- cross-view primitives ---------- */
|
||||
.mono {
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.dim {
|
||||
color: var(--ink-3);
|
||||
}
|
||||
|
||||
.tnum {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Empty / not-yet-loaded states. Sentence case, no exclamation marks —
|
||||
say what is missing and what to do about it. */
|
||||
.emptystate {
|
||||
padding: 40px;
|
||||
max-width: 60ch;
|
||||
color: var(--ink-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.emptystate h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 16px;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.emptystate p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.emptystate code {
|
||||
font-family: var(--mono);
|
||||
font-size: 12px;
|
||||
background: var(--press);
|
||||
padding: 1px 4px;
|
||||
}
|
||||
Reference in New Issue
Block a user