Skip to content

Build GovGraph design system foundation - #5

Merged
daviddiviny merged 3 commits into
mainfrom
codex/design-system-foundation
Apr 7, 2026
Merged

daviddiviny merged 3 commits into
mainfrom
codex/design-system-foundation

Conversation

@daviddiviny

Copy link
Copy Markdown
Owner

Summary

  • add a typed GovGraph token system in @govgraph/ui, generate committed CSS variables, and keep legacy --govgraph-* aliases in place during the migration
  • expand the shared UI library with layout, navigation, record, data, and state components, plus a /design preview route and usage guide
  • migrate the live home, node, layout, and not-found pages onto the new shared design system while preserving the newer Sprint 2 data/content already on main
  • add UI guardrail tests and sync the lockfile for the new UI tooling

Testing

  • pnpm lint
  • pnpm typecheck
  • pnpm test
  • pnpm build
  • browser smoke checks with Playwright screenshots for /, /design, and /nodes/person-ben-carroll

Risks

  • broad shared styling change across app layout, globals, and the main user-facing pages
  • token CSS is now generated and committed, so future token edits need pnpm --filter @govgraph/ui generate:tokens

Copy link
Copy Markdown
Owner Author

Verified this branch after rebasing onto main.

What changed:

  • added the shared GovGraph token system and generated stylesheet
  • expanded the shared UI library and migrated the main web pages onto it
  • added a /design preview page and design-system docs
  • kept newer main content that landed during the rebase, including the updated home-page sections and node-page website link

Checks run locally:

  • pnpm lint
  • pnpm typecheck
  • pnpm test
  • pnpm build

Manual verification:

  • checked /
  • checked /design
  • checked /nodes/person-ben-carroll

Current PR state:

  • branch is clean and PR is mergeable
  • no review comments or review threads are open right now
  • the repo has no protected-branch rules or required checks on main
  • the claude-review workflow is still showing as in progress, but it is not configured as a required merge gate in this repo

@claude is your feedback properly addressed?

@claude

claude Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Claude finished @daviddiviny's task in 2m 21s —— View job


Review: Design System Foundation

  • Read CLAUDE.md for repo guidelines
  • Review token system and generated CSS
  • Review new UI components
  • Review migrated pages (home, node, layout, not-found)
  • Assess overall PR quality and provide final verdict

The PR is in good shape and is ready to merge. The token architecture is sound, the CSS generation guardrail test is a strong pattern, and the page migrations are clean. A few things worth fixing either before merge or in follow-up:


Issues

Medium — stale copy in not-found.tsx

apps/web/app/not-found.tsx:17-19 still reads:

"The sprint 1 prototype only includes the current ministry, current portfolio mapping, and department-backed portfolio relationships."

Sprint 2 data is live (public entities, budget documents, VPSC directory). This message will mislead real users hitting a 404. Fix this →

Medium — rowIndex used as React key in DataTable

packages/ui/src/data-table.tsx:118:

sortedRows.map((row, rowIndex) => (
  <tr key={rowIndex} ...>

Array indices as keys are unsafe when the list is sorted — React will reuse stale DOM nodes across re-renders. Since DataTableRow is a plain Record<string, DataTableValue>, there's no guaranteed stable id. A reasonable fix is a composite key from all cell values:

key={columns.map((c) => row[c.key] ?? "").join("|")}

Or add an optional rowKey prop to DataTable that callers can supply. Fix this →


Minor observations (can be deferred)

scripts/generate-token-css.ts excluded from typecheck

packages/ui/tsconfig.json only includes src/**/*, so scripts/generate-token-css.ts is never type-checked — only transpiled at runtime via tsx. The script is trivial today, but as it grows it could silently accumulate errors. Either extend the include array or add a tsconfig.scripts.json targeting that file.

gap-4 raw Tailwind class in relationship-list.tsx

apps/web/app/_components/relationship-list.tsx:23 uses gap-4 (raw Tailwind) while every other component uses gap-[var(--gg-space-4)] (token reference). Minor inconsistency. Fix this →

humanizeNodeType not exported

node-type-badge.tsx has a private humanizeNodeType helper but nodes/[slug]/page.tsx:72,120 duplicates nodeType.replace(/_/g, " ") inline twice. Exporting humanizeNodeType from the UI package would remove the duplication.

Hardcoded rgba in SiteHeader and globals.css

site-header.tsx:21 uses rgba(246,241,230,0.95) (paper colour at 95% opacity) and globals.css:56 uses rgba(185, 74, 55, 0.18) (accent at 18% opacity) — both are values the token system could express. Not a runtime problem but worth closing the gap during the next token pass.


What's working well

  • The token CSS generation + committed artifact + drift-detection test (index.test.ts:21) is a clean pattern — prevents silent divergence.
  • data-table-sort.ts is cleanly isolated from the React component and independently tested.
  • Node type colours map directly to token keys — no magic strings at the usage sites.
  • Legacy --govgraph-* aliases are maintained while the migration window is open, which is the right call.
  • relationship-list.tsx now uses a composite key (${edgeType}-${direction}-${node.id}) instead of an index — that's correct.

The stale 404 copy and the rowIndex key are the only items I'd want addressed before merging into main.

Copy link
Copy Markdown
Owner Author

Addressed the actionable review items on the latest commit.

What changed:

  • updated the 404 page copy so it reflects the current snapshot scope instead of the old Sprint 1 wording
  • replaced the sortable table's index-based row key with a stable value-based key lookup and added focused tests around that logic
  • aligned RelationshipList spacing with the token-based gap convention
  • switched the node page to use the existing humanizeNodeType presenter helper instead of duplicating the string replacement inline

Checks run:

  • pnpm test
  • pnpm typecheck
  • pnpm build

Manual verification:

  • checked the 404 page in the browser and confirmed the updated copy renders correctly
  • checked /nodes/person-ben-carroll in the browser and confirmed the page still renders correctly after the helper cleanup

Notes on the smaller review observations:

  • the humanizeNodeType duplication is now cleaned up on the node page without changing the UI package API
  • I did not expand scope into the token-script typecheck or rgba token follow-ups in this pass

@claude is your feedback properly addressed?

@claude

claude Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Claude finished @daviddiviny's task in 48s —— View job


Review: Feedback Follow-up

  • Read relevant changed files
  • Verify stale 404 copy fix
  • Verify stable row key fix and tests
  • Verify gap token alignment in relationship-list.tsx
  • Verify humanizeNodeType deduplication on node page

Yes, all four actionable items from the previous review are properly addressed.

Stale 404 copy — not-found.tsx:17-19 now reads:

"The current snapshot covers the ministry, portfolio mapping, departments, public entities, budget documents, and the VPSC directory."

Accurate and no longer Sprint 1-scoped. ✅

Stable row key in DataTable — The fix is better than what I suggested. Rather than a simple value join, data-table-row-key.ts pre-builds a Map<Row, string> keyed by object identity before sorting. Duplicate rows get differentiated via an occurrence counter (::0, ::1), so the key is both stable across sorts and unique even when rows are value-identical. The tests in data-table-row-key.test.ts exercise both the signature builder and the duplicate-row case after sorting. ✅

Gap token in relationship-list.tsx — gap-4 → gap-[var(--gg-space-4)] on line 23. Consistent with the rest of the codebase. ✅

humanizeNodeType deduplication — nodes/[slug]/page.tsx now imports and calls humanizeNodeType at both usage sites (lines 72, 120). No inline replace duplication remains. ✅


The two deferred observations (token-script typecheck, rgba token follow-ups) are fine to carry forward — they were always non-blocking.

This PR is ready to merge.

@daviddiviny
daviddiviny merged commit 70c44b2 into main Apr 7, 2026
1 check 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