Refactor the List-specific screen into a data-driven, reusable viewer: - generic Blueprint type + shared LoadState machine + registry - vue-router: / (gallery) and /b/:slug (illustration) - BlueprintViewer renders any blueprint; specimens stay bespoke - add Grid blueprint (6 functions incl. Position) + GridSpecimen
71 lines
4.0 KiB
Markdown
71 lines
4.0 KiB
Markdown
# Design — `blueprints`
|
|
|
|
Decisions for building `blueprints` out from a single List illustration into a
|
|
gallery of many. Terminology: see [CONTEXT.md](CONTEXT.md).
|
|
|
|
## D1 · Content sourcing: hand-authored typed data + bespoke specimen
|
|
|
|
Each blueprint is a **typed TS data module** (`src/data/<name>Blueprint.ts`),
|
|
transcribed by hand from its ontology README, paired with a **bespoke Specimen**
|
|
component. The generic **Viewer** renders everything else (Readout, composition map,
|
|
state machine) from that data.
|
|
|
|
- **Why not parse the ontology at build time?** The Specimen must be hand-built for
|
|
every blueprint regardless (the ontology only provides an ASCII sketch), so parsing
|
|
would automate only the cheap, structured text — at the cost of fragile
|
|
markdown/mermaid parsing and a build-time coupling to the ontology repo's exact
|
|
format. Not worth it.
|
|
- **Source of truth** stays the `blueprint-ontology` repo; the data modules are a
|
|
faithful transcription, cited in each module's header.
|
|
|
|
Structural split this implies:
|
|
|
|
| Part | Generic (data-driven) | Bespoke (per blueprint) |
|
|
| ---------------------------------- | ------------------------------------ | ----------------------------------- |
|
|
| Chrome (title block, tabs, legend) | ✓ | |
|
|
| Readout (dossier per function) | ✓ | |
|
|
| Composition map | ✓ (from `extends` + `composes` data) | |
|
|
| State machine | ✓ (from nodes/edges data) | |
|
|
| Specimen | | ✓ component slotted into the Viewer |
|
|
|
|
## D2 · Routing: vue-router, URL per blueprint
|
|
|
|
Add `vue-router`. Routes: `/` → Gallery, `/b/:slug` → the blueprint's illustration
|
|
(e.g. `/b/list`). Deep-linkable and shareable; browser back/forward works. The nginx
|
|
SPA fallback (`try_files … /index.html`) already serves client routes, so no server
|
|
change is needed. A blueprint registry (`src/data/blueprints.ts`) maps `slug →
|
|
{ data module, specimen component, meta }` and is the single source both the router
|
|
and the Gallery read from.
|
|
|
|
## D3 · Gallery: illustrated-only, grows over time
|
|
|
|
The Gallery lists **only** blueprints that have an illustration; it grows as we add
|
|
them. No greyed "planned" cards. Rationale: keeps the landing clean and truthful, and
|
|
avoids maintaining metadata for 45 not-yet-built entries. A blueprint appears in the
|
|
Gallery precisely when it is registered in `src/data/blueprints.ts`.
|
|
|
|
## D4 · Build-out slice #1: foundation + Grid
|
|
|
|
**Foundation (refactor, no UX change to List):**
|
|
|
|
- `pnpm add vue-router`; `App.vue` → thin shell with a header (link home) + `<RouterView/>`.
|
|
- `src/views/GalleryView.vue` (`/`) — cards from the registry.
|
|
- `src/views/BlueprintView.vue` (`/b/:slug`) — resolves the registry entry, renders the Viewer.
|
|
- `src/components/BlueprintViewer.vue` — the **generic Viewer**, generalized from the
|
|
current List-specific `App.vue`: title block, legend, function tabs + full view,
|
|
two panes, optional composition map + state machine, footer. Props: a `Blueprint`
|
|
object + the blueprint's Specimen component (injected via `<component :is>`).
|
|
- Generic `Blueprint` type in `src/data/blueprint.ts` (signature, functions,
|
|
coreInvariants, optional composition, optional stateMachine, meta). `listBlueprint.ts`
|
|
conforms to it. Specimens move to `src/specimens/`.
|
|
- `src/data/blueprints.ts` — registry: `slug → { meta, blueprint, specimen }`.
|
|
|
|
**Content:** `gridBlueprint.ts` + `src/specimens/GridSpecimen.vue` (2D tile grid).
|
|
|
|
**Ships:** Gallery listing List + Grid; `/b/list` (same UX, refactored) and `/b/grid`.
|
|
|
|
**Gates before push:** `pnpm build` clean · `pnpm lint` · `pnpm fmt`; then commit → push
|
|
(auto-deploys) → verify `https://blueprints.apoena.dev`.
|
|
|
|
Subsequent slices add one blueprint each (Table, Feed, …).
|