Pond knowledge graph view (Obsidian-like) #112

Closed
opened 2026-07-14 09:32:44 +02:00 by fable-5 · 1 comment
Collaborator

Context

An interactive per-pond graph: pages as nodes, resolved wikilinks as edges, phantom targets as dashed nodes — force layout with zoom/pan, click to open a page. Rendering must be fully self-contained (hard zero-external-request rule).

Scope

  • New dependency d3-force in apps/web/package.json (bundled like lucide-react; ~10 kB gz incl. transitive d3-quadtree/d3-dispatch/d3-timer; no DOM or network deps). No d3-zoom/d3-selection — zoom/pan hand-rolled.
  • Route /p/:pondSlug/graph in apps/web/src/App.tsx (static segment ranked above :pageSlug, same documented reserved-slug gap as trash/settings) + an entry point in the sidebar.
  • apps/web/src/graph/GraphView.tsx (new dir): SVG renderer — simulation ticks into React state; wheel zoom + pointer pan on a <g transform>; node drag pinning optional; node click navigates to /p/<pond>/<slug>.
  • Phantom nodes dashed; clicking one offers “create page” (POST /ponds/:id/pages with the slug's title), after which the node renders solid (phantom resolution is existing server behavior).
  • Node fill = first label's color (fallback DEFAULT_LABEL_COLOR), legend listing the labels present in the pond.
  • Cap: run the layout up to 500 nodes; above, show a translated “graph too large” notice.
  • New i18n namespace graph (de+en). data-testid on every node for e2e.

Acceptance criteria

  • Graph shows exactly the readable subgraph from GET /ponds/:pondId/links; zoom/pan and click-to-open work.
  • Phantom flow creates the page and updates the graph.
  • Legend colors match node fills; unlabeled nodes use the default color.
  • Zero external requests (covered by the existing off-origin assertion pattern in the fonts spec).

Technical notes

  • SVG over canvas deliberately: pond sizes are small and SVG nodes are Playwright-clickable.
  • Reuse the TanStack query for /ponds/:id/links; nodes' labelIds come with the payload.

Dependencies

Requires #111.

Size

~2 days.

## Context An interactive per-pond graph: pages as nodes, resolved wikilinks as edges, phantom targets as dashed nodes — force layout with zoom/pan, click to open a page. Rendering must be fully self-contained (hard zero-external-request rule). ## Scope - New dependency `d3-force` in `apps/web/package.json` (bundled like `lucide-react`; ~10 kB gz incl. transitive `d3-quadtree`/`d3-dispatch`/`d3-timer`; no DOM or network deps). **No** `d3-zoom`/`d3-selection` — zoom/pan hand-rolled. - Route `/p/:pondSlug/graph` in `apps/web/src/App.tsx` (static segment ranked above `:pageSlug`, same documented reserved-slug gap as `trash`/`settings`) + an entry point in the sidebar. - `apps/web/src/graph/GraphView.tsx` (new dir): SVG renderer — simulation ticks into React state; wheel zoom + pointer pan on a `<g transform>`; node drag pinning optional; node click navigates to `/p/<pond>/<slug>`. - Phantom nodes dashed; clicking one offers “create page” (`POST /ponds/:id/pages` with the slug's title), after which the node renders solid (phantom resolution is existing server behavior). - Node fill = first label's `color` (fallback `DEFAULT_LABEL_COLOR`), legend listing the labels present in the pond. - Cap: run the layout up to 500 nodes; above, show a translated “graph too large” notice. - New i18n namespace `graph` (de+en). `data-testid` on every node for e2e. ## Acceptance criteria - [ ] Graph shows exactly the readable subgraph from `GET /ponds/:pondId/links`; zoom/pan and click-to-open work. - [ ] Phantom flow creates the page and updates the graph. - [ ] Legend colors match node fills; unlabeled nodes use the default color. - [ ] Zero external requests (covered by the existing off-origin assertion pattern in the fonts spec). ## Technical notes - SVG over canvas deliberately: pond sizes are small and SVG nodes are Playwright-clickable. - Reuse the TanStack query for `/ponds/:id/links`; nodes' `labelIds` come with the payload. ## Dependencies Requires #111. ## Size ~2 days.
fable-5 added this to the M12 — Page hierarchy & knowledge graph milestone 2026-07-14 09:32:44 +02:00
fable-5 added the
frontend
label 2026-07-14 09:32:44 +02:00
Author
Collaborator

Implemented in dbbe229. /p/:pondSlug/graph (static segment, same reserved-slug gap as trash/settings) renders the pond graph: label-colored nodes with a legend, wikilink edges, dashed phantom nodes whose click creates the page. The renderer is a self-contained SVG force graph — only d3-force is bundled (~11 kB gz, no d3 DOM/zoom modules, zero external requests), synchronous layout, pointer-math zoom/pan/drag, and a data-testid per node for the e2e pack. 500-node cap notice; sidebar footer links every member to the graph. Verified live including the phantom-create flow.

Implemented in dbbe229. `/p/:pondSlug/graph` (static segment, same reserved-slug gap as trash/settings) renders the pond graph: label-colored nodes with a legend, wikilink edges, dashed phantom nodes whose click creates the page. The renderer is a self-contained SVG force graph — only `d3-force` is bundled (~11 kB gz, no d3 DOM/zoom modules, zero external requests), synchronous layout, pointer-math zoom/pan/drag, and a data-testid per node for the e2e pack. 500-node cap notice; sidebar footer links every member to the graph. Verified live including the phantom-create flow.
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#112
No description provided.