mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-24 06:53:52 +08:00
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.
203 lines
4.6 KiB
CSS
203 lines
4.6 KiB
CSS
/* =====================================================================
|
|
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;
|
|
}
|