Goal
Replace raw node IDs in tooltips and breadcrumbs with meaningful labels. Single shared tooltip component across all deck.gl frames.
src/lib/derive-label.ts
Priority chain:
node.properties.title (categorical value)
node.properties.source (categorical — filename/URL)
- First 80 chars of
node.text truncated at word boundary + "…"
- Fallback:
node.id
src/components/NodeTooltip.tsx
- Rendered as a React portal at
document.body
- Positioned near cursor via
pointerX/Y state (tracked in a thin mouse-move listener)
- Triggered by
selectionStore.hovered — visible when any node is hovered
- Shows:
- Type badge (colored with
NodeType.display.color)
- Derived label (bold)
- Text preview (2 lines max, truncated)
- Annotation count chips: 🌍
n geo · 📅 n temporal · 👤 n entity
- Dismisses when
hovered is null
- z-index above all frames
Integration
Acceptance criteria
- Hovering any node in any frame shows tooltip within 100ms
- Tooltip shows meaningful text, not raw IDs
- Disappears cleanly when cursor leaves a node
Goal
Replace raw node IDs in tooltips and breadcrumbs with meaningful labels. Single shared tooltip component across all deck.gl frames.
src/lib/derive-label.tsPriority chain:
node.properties.title(categorical value)node.properties.source(categorical — filename/URL)node.texttruncated at word boundary + "…"node.idsrc/components/NodeTooltip.tsxdocument.bodypointerX/Ystate (tracked in a thin mouse-move listener)selectionStore.hovered— visible when any node is hoveredNodeType.display.color)n geo· 📅n temporal· 👤n entityhoveredis nullIntegration
<NodeTooltip />once inAppShellhovertoselectionStore— no per-frame changes neededderiveLabelinstead of raw IDsAcceptance criteria