Skip to content

KS77: Design system foundation + P0 graph polish#18

Merged
Liorrr merged 8 commits intomasterfrom
feat/ks77-viz-design-system
Apr 10, 2026
Merged

KS77: Design system foundation + P0 graph polish#18
Liorrr merged 8 commits intomasterfrom
feat/ks77-viz-design-system

Conversation

@Liorrr
Copy link
Copy Markdown
Contributor

@Liorrr Liorrr commented Apr 10, 2026

Summary

  • Design system foundation — Tailwind 4.0 @theme block with 4-surface color hierarchy (canvas/base/elevated/overlay), 30 design tokens (colors, typography, animation, z-index, spacing), prefers-reduced-motion support
  • 6 reusable UI components — Button, IconButton, Badge, Toggle, Panel, StateDisplay in src/components/ui/
  • Full component migration — All existing components migrated from hardcoded colors to design tokens
  • P0: Node size by importance — Log-scale 10-40px with SizeLegend overlay
  • P0: Louvain community colors — Tableau10 palette via deterministic hash with CommunityLegend overlay
  • P0: Camera transitions — 250ms ease-out animations on select/drill/expand via useCameraTransition hook
  • 10 micro-improvements — Escape close, click-outside dropdown, Ctrl+K search focus, node/edge count, legend fade, community labels, loading skeleton, badge tooltip, sidebar collapse, empty state
  • QA infrastructure — STP (test plan), STD (30 test cases), automated preflight script

Stats

  • 25 files changed, +1516 / -302
  • 7 commits
  • 30/30 structured QA test cases PASS
  • 8/8 regression checks PASS
  • Designer reviewed and approved all changes
  • tsc --noEmit clean, vite build clean (375KB JS, 27KB CSS)
  • Tauri binary compiles and renders correctly

Known issues (pre-existing, not introduced)

  • Daemon Hebbian graph endpoints (/api/graph/neighbors, /api/memory_related, /api/graph/subgraph) deadlock under load. Frontend uses /api/echo workaround for drill-in and expand.
  • Daemon response times 15-60s on some requests (performance, not frontend issue).

Test plan

  • Preflight: daemon v0.7.0 health, overview/echo/memory_get endpoints, Vite server
  • Galaxy view: graph loads, 30 communities, zoom controls, no errors
  • Drill-in: community click, legends appear, no daemon crash
  • Neighborhood: expand node, center + neighbors, edges visible
  • Detail panel: category badge, content, metrics, expand/copy buttons
  • Search: dropdown results, click navigates, Escape closes
  • Navigation: back to galaxy, home button, refresh, zoom in/out
  • Visual polish: no pure white, WCAG focus rings, reduced-motion, dark theme
  • Regression: Escape close, click-outside, Ctrl+K, node count, sidebar collapse, legend fade, skeleton, badge tooltip
  • Tauri build: binary compiles, window launches, graph renders in WebView2

🤖 Generated with Claude Code

Liorrr and others added 7 commits April 10, 2026 01:22
- Add document keydown listener in NodeDetail useEffect
- Guard: only registers when selectedNode is not null
- Proper cleanup on unmount/dependency change
- Designer approved: correct a11y pattern, no side effects

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-select center node in expandNode() so detail panel appears
  after search→click (fixes DP-01)
- Click-outside closes SearchBar dropdown (mousedown + ref)
- Node/edge count display in toolbar for cluster/neighborhood views
- Designer approved: no race conditions, correct cleanup, tokens intact

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Smooth opacity fade on SizeLegend + CommunityLegend (duration-panel,
  motion-reduce:transition-none, pointer-events-none when hidden)
- Ctrl+K keyboard shortcut focuses SearchBar input
- Placeholder updated: "Search memories... (Ctrl+K)"
- Designer approved: correct tokens, reduced-motion respected,
  no layout impact from always-rendered absolute legends

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CommunityLegend matches community members to clusters via top_members
  overlap, shows truncated summary (20 chars) or "Group A/B/C" fallback
- aria-hidden={!visible} on SizeLegend + CommunityLegend for screen readers
- Panel component: new optional aria-hidden prop passthrough
- Designer approved: correct a11y, no token regressions, layout safe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CommunityPanel shows 5 shimmer skeleton rectangles during initial load
  (staggered widths, animate-pulse, motion-reduce:animate-none, aria-hidden)
- Badge count variant shows "N members" tooltip on hover
- Designer approved skeleton: correct tokens, reduced-motion, no layout shift

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sidebar collapses to 48px icon strip (Layers/Search/Settings)
  with PanelLeftClose expand button, smooth transition-all duration-panel
- sidebarCollapsed + toggleSidebar added to graphStore
- Empty state overlay on canvas when clusters=0 && !loading:
  Network icon + "No memories yet" heading
- motion-reduce:transition-none on sidebar animation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Refactored CommunityPanel to single Panel element with dynamic width
  so CSS transition-all actually animates (was mount/unmount swap)
- Simplified collapsed strip to Layers icon only (removed misleading
  Search/Settings no-op icons)
- overflow-hidden prevents content bleed during transition

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 10, 2026

Greptile Summary

This PR establishes a design system foundation (Tailwind 4 @theme block with 30 tokens, 4-surface color hierarchy) and migrates all existing UI to design tokens, ships 6 new reusable components (Button, IconButton, Badge, Toggle, Panel, StateDisplay), and delivers three P0 graph features: log-scale node sizing, Louvain community colours (Tableau10), and 250 ms camera transitions. It also adds 10 micro-improvements (Escape close, click-outside, Ctrl+K, node/edge counts, sidebar collapse, etc.) and a QA test suite.

Key changes:

  • globals.css replaces the old :root variables with a Tailwind 4 @theme block; prefers-reduced-motion collapses all durations to 1 ms.
  • graphStore.ts replaces fetchNeighbors/fetchRelated (deadlocking endpoints) with searchMemories workarounds, adds Louvain community detection, log-scale sizing, and sidebar/community-map state.
  • GraphCanvas.tsx wires useCameraTransition for select/drill/expand, moves zoom controls into SigmaContainer, and adds empty-state + legend overlays.
  • New src/components/ui/ directory contains all reusable primitives with consistent focus rings, reduced-motion guards, and token-based styling.

Confidence Score: 4/5

Safe to merge after the empty-content_preview guard is added; the secondary-button hover and camera double-animation are non-blocking polish items.

The PR is large (+1516/−302) but well-structured: design tokens are cleanly consolidated, UI components follow consistent patterns, and the Louvain + sizing logic is correct. The previously flagged double-fetchMemoryGet in expandNode is fixed in this revision. One P1 remains: drillIntoCommunity passes an unguarded content_preview string directly to searchMemories, which silently misbehaves on blank content. The P2s (inverted secondary-button hover, double camera animation on expand) are cosmetic and easy to follow up. Everything else — focus rings, motion-reduce, Louvain hashing, edge-cap logic — is correct.

crates/shrimpk-viz/web/src/stores/graphStore.ts (empty-query guard), crates/shrimpk-viz/web/src/components/ui/Button.tsx (hover colour direction)

Important Files Changed

Filename Overview
crates/shrimpk-viz/web/src/stores/graphStore.ts Core state machine; replaces deadlocking API calls with search workarounds and adds Louvain community detection. Contains an unguarded empty-string query path when content_preview is blank.
crates/shrimpk-viz/web/src/components/GraphCanvas.tsx Adds camera transitions, zoom controls, legends, and empty state; a minor double-animation artefact occurs during node expand because LayoutRunner's fit-all overrides the select animation.
crates/shrimpk-viz/web/src/styles/globals.css Well-structured Tailwind 4 @theme block with complete token set, reduced-motion support, and clean migration from old :root variables.
crates/shrimpk-viz/web/src/lib/categoryColors.ts Single source of truth for node/badge colors; deterministic Louvain community→Tableau10 mapping via hashCode is correct and collision-safe.
crates/shrimpk-viz/web/src/hooks/useCameraTransition.ts Clean hook wrapping Sigma camera animations with consistent duration/easing; correctly filters invalid node IDs before animating.
crates/shrimpk-viz/web/src/components/ui/Button.tsx Well-structured with forwardRef, focus rings, and motion-reduce. The secondary variant hover colour is inverted (goes darker instead of lighter).
crates/shrimpk-viz/web/src/components/ui/IconButton.tsx Minimal, correct; enforces tooltip prop for aria-label, handles active/disabled states cleanly.
crates/shrimpk-viz/web/src/components/ui/Badge.tsx Discriminated union props cleanly separate label/category/count variants; category badge falls back to Default via getCategoryBadge.
crates/shrimpk-viz/web/src/components/SearchBar.tsx Adds click-outside, Ctrl+K focus, and Escape close correctly with proper cleanup in useEffect returns.
crates/shrimpk-viz/web/src/components/CommunityLegend.tsx Fade-in/out legend that shows top 10 communities sorted by size; cluster summary matching is a best-effort heuristic, not a concern.
crates/shrimpk-viz/web/src/components/NodeDetail.tsx Clean migration to design tokens and UI components; Escape-to-close effect has correct cleanup.
crates/shrimpk-viz/web/src/components/CommunityPanel.tsx Sidebar collapse added with correct animation class; loading skeleton and focus rings are a good addition.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant CP as CommunityPanel
    participant GS as graphStore
    participant API as Daemon API
    participant GC as GraphCanvas

    U->>CP: Click cluster
    CP->>GS: drillIntoCommunity(label)
    GS->>GS: Guard: cluster exists & top_member content non-empty
    GS->>API: searchMemories(content_preview, 100)
    API-->>GS: EchoResults[]
    GS->>GS: Build graph nodes (log-scale sizing)
    GS->>GS: Create O(n²) similarity edges (cap 200)
    GS->>GS: assignCommunityColors → Louvain → Tableau10
    GS-->>GC: set { graph, communityMap, zoomLevel:cluster }
    GC->>GC: LayoutRunner runs ForceAtlas2 (~100 frames)
    GC->>GC: animateToNodes(allNodes) — fit camera

    U->>GC: Click node
    GC->>GS: selectNode(id)
    GS->>API: fetchMemoryGet(id)
    API-->>GS: MemoryDetail
    GS-->>GC: set { selectedNode, selectedDetail }
    GC->>GC: animateToNode(id) — 250ms camera transition

    U->>GC: Click Expand neighbors
    GC->>GS: expandNode(id)
    GS->>API: fetchMemoryGet(id)
    API-->>GS: center MemoryDetail
    GS->>API: searchMemories(center.content slice 200, 20)
    API-->>GS: neighbor EchoResults
    GS->>GS: Build neighborhood graph + Louvain colors
    GS-->>GC: set { graph, selectedNode:id, selectedDetail:center }
    GC->>GC: animateToNode(id) immediate
    GC->>GC: LayoutRunner → animateToNodes(all) after layout
Loading

Reviews (2): Last reviewed commit: "fix(viz): address Greptile PR review fin..." | Re-trigger Greptile

Comment thread crates/shrimpk-viz/web/src/stores/graphStore.ts Outdated
- P1: Eliminate double fetchMemoryGet in expandNode — pass already-fetched
  center as selectedDetail directly instead of re-fetching via selectNode
- P2: Move d3-scale-chromatic import to top of categoryColors.ts
- P2: Remove dead SIDEBAR_COLLAPSE_ICONS export from layout.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Liorrr Liorrr merged commit 8ba96e2 into master Apr 10, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant