From 2e2e2a5f378a54d661fa6daaa7be4f7904560987 Mon Sep 17 00:00:00 2001 From: David Diviny Date: Wed, 8 Apr 2026 06:14:48 +1000 Subject: [PATCH 1/3] Build GovGraph design system foundation --- .../web/app/_components/relationship-list.tsx | 49 ++- apps/web/app/_components/search-form.tsx | 4 +- apps/web/app/design/page.tsx | 279 ++++++++++++++++++ apps/web/app/globals.css | 42 ++- apps/web/app/layout.tsx | 64 +++- apps/web/app/nodes/[slug]/page.tsx | 215 +++++++++----- apps/web/app/not-found.tsx | 46 +-- apps/web/app/page.tsx | 277 ++++++++--------- docs/design-system.md | 25 ++ packages/ui/package.json | 12 +- packages/ui/scripts/generate-token-css.ts | 10 + packages/ui/src/badge.tsx | 30 +- packages/ui/src/breadcrumb.tsx | 45 +++ packages/ui/src/button.tsx | 32 +- packages/ui/src/card.tsx | 21 +- packages/ui/src/data-table-sort.test.ts | 55 ++++ packages/ui/src/data-table-sort.ts | 80 +++++ packages/ui/src/data-table.tsx | 141 +++++++++ packages/ui/src/empty-state.tsx | 41 +++ packages/ui/src/footer.tsx | 42 +++ packages/ui/src/index.ts | 19 ++ packages/ui/src/input.tsx | 2 +- packages/ui/src/key-value.tsx | 32 ++ packages/ui/src/metric-bar.tsx | 58 ++++ packages/ui/src/node-card.tsx | 43 +++ packages/ui/src/node-type-badge.tsx | 62 ++++ packages/ui/src/page-shell.tsx | 18 ++ packages/ui/src/section-header.tsx | 52 ++++ packages/ui/src/site-header.tsx | 37 +++ packages/ui/src/skeleton.tsx | 31 ++ packages/ui/src/source-card.tsx | 44 +++ packages/ui/src/stat-card.tsx | 32 ++ packages/ui/src/textarea.tsx | 18 ++ packages/ui/src/timeline-entry.tsx | 45 +++ packages/ui/src/tokens/animation.ts | 10 + packages/ui/src/tokens/colors.ts | 97 ++++++ packages/ui/src/tokens/generate-css.ts | 49 +++ packages/ui/src/tokens/generated.css | 143 +++++++++ packages/ui/src/tokens/index.test.ts | 26 ++ packages/ui/src/tokens/index.ts | 46 +++ packages/ui/src/tokens/radii.ts | 8 + packages/ui/src/tokens/shadows.ts | 5 + packages/ui/src/tokens/spacing.ts | 15 + packages/ui/src/tokens/typography.ts | 57 ++++ packages/ui/src/tooltip.tsx | 27 ++ packages/ui/tsconfig.json | 3 + 46 files changed, 2173 insertions(+), 316 deletions(-) create mode 100644 apps/web/app/design/page.tsx create mode 100644 docs/design-system.md create mode 100644 packages/ui/scripts/generate-token-css.ts create mode 100644 packages/ui/src/breadcrumb.tsx create mode 100644 packages/ui/src/data-table-sort.test.ts create mode 100644 packages/ui/src/data-table-sort.ts create mode 100644 packages/ui/src/data-table.tsx create mode 100644 packages/ui/src/empty-state.tsx create mode 100644 packages/ui/src/footer.tsx create mode 100644 packages/ui/src/key-value.tsx create mode 100644 packages/ui/src/metric-bar.tsx create mode 100644 packages/ui/src/node-card.tsx create mode 100644 packages/ui/src/node-type-badge.tsx create mode 100644 packages/ui/src/page-shell.tsx create mode 100644 packages/ui/src/section-header.tsx create mode 100644 packages/ui/src/site-header.tsx create mode 100644 packages/ui/src/skeleton.tsx create mode 100644 packages/ui/src/source-card.tsx create mode 100644 packages/ui/src/stat-card.tsx create mode 100644 packages/ui/src/textarea.tsx create mode 100644 packages/ui/src/timeline-entry.tsx create mode 100644 packages/ui/src/tokens/animation.ts create mode 100644 packages/ui/src/tokens/colors.ts create mode 100644 packages/ui/src/tokens/generate-css.ts create mode 100644 packages/ui/src/tokens/generated.css create mode 100644 packages/ui/src/tokens/index.test.ts create mode 100644 packages/ui/src/tokens/index.ts create mode 100644 packages/ui/src/tokens/radii.ts create mode 100644 packages/ui/src/tokens/shadows.ts create mode 100644 packages/ui/src/tokens/spacing.ts create mode 100644 packages/ui/src/tokens/typography.ts create mode 100644 packages/ui/src/tooltip.tsx diff --git a/apps/web/app/_components/relationship-list.tsx b/apps/web/app/_components/relationship-list.tsx index 818f4f8..9692ef4 100644 --- a/apps/web/app/_components/relationship-list.tsx +++ b/apps/web/app/_components/relationship-list.tsx @@ -1,9 +1,9 @@ import Link from "next/link"; import type { RelatedNode } from "@govgraph/domain"; -import { Badge, Card } from "@govgraph/ui"; +import { Badge, EmptyState, NodeCard, NodeTypeBadge } from "@govgraph/ui"; -import { describeRelationship, humanizeNodeType } from "../_lib/presenters"; +import { describeRelationship } from "../_lib/presenters"; type RelationshipListProps = { relatedNodes: RelatedNode[]; @@ -12,37 +12,34 @@ type RelationshipListProps = { export function RelationshipList({ relatedNodes }: RelationshipListProps) { if (relatedNodes.length === 0) { return ( - -

- No connected records are available for this node yet. -

-
+ ); } return (
{relatedNodes.map((entry) => ( - -
- {describeRelationship(entry)} - {humanizeNodeType(entry.node.nodeType)} -
- - {entry.node.canonicalName} - - {entry.node.description ? ( -

- {entry.node.description} -

- ) : null} -
+ badges={ + <> + {describeRelationship(entry)} + + + } + description={entry.node.description} + title={ + + {entry.node.canonicalName} + + } + /> ))}
); diff --git a/apps/web/app/_components/search-form.tsx b/apps/web/app/_components/search-form.tsx index 5b4826b..af357a3 100644 --- a/apps/web/app/_components/search-form.tsx +++ b/apps/web/app/_components/search-form.tsx @@ -4,12 +4,14 @@ type SearchFormProps = { defaultValue?: string; action?: string; placeholder?: string; + size?: "md" | "lg"; }; export function SearchForm({ defaultValue = "", action = "/", placeholder = "Search ministers, portfolios, and departments", + size = "lg", }: SearchFormProps) { return (
@@ -20,7 +22,7 @@ export function SearchForm({ aria-label="Search the government map" className="min-w-0 flex-1" /> -
diff --git a/apps/web/app/design/page.tsx b/apps/web/app/design/page.tsx new file mode 100644 index 0000000..3fe46dd --- /dev/null +++ b/apps/web/app/design/page.tsx @@ -0,0 +1,279 @@ +import Link from "next/link"; + +import { nodeTypes } from "@govgraph/domain"; +import { + Badge, + Button, + Card, + DataTable, + EmptyState, + KeyValue, + MetricBar, + NodeCard, + NodeTypeBadge, + PageShell, + SectionHeader, + Skeleton, + SourceCard, + StatCard, + Textarea, + TimelineEntry, + Tooltip, + Input, +} from "@govgraph/ui"; + +const budgetRows = [ + { agency: "Treasury and Finance", budget: 8300000000, workforce: 1450 }, + { agency: "Transport and Planning", budget: 16700000000, workforce: 3940 }, + { agency: "Education", budget: 23200000000, workforce: 2180 }, +] as const; + +const budgetColumns = [ + { key: "agency", header: "Agency", sortable: true }, + { + key: "budget", + header: "Budget", + sortable: true, + align: "right" as const, + format: "currency" as const, + }, + { + key: "workforce", + header: "Workforce", + sortable: true, + align: "right" as const, + format: "number" as const, + }, +] as const; + +export default function DesignPage() { + return ( +
+ +
+
+ GovGraph Design System + Live preview route +
+
+

+ Register aesthetic +

+

+ Typed tokens, shared components, and a calmer way to build the + atlas. +

+

+ This page previews the shared system that now drives the live + pages. It is where new patterns should be checked before they land + in the atlas proper. +

+
+
+ +
+ + + +
+ +
+
+ + +
+ + + +
+
+ Neutral + Accent + Success + Warning +
+
+ +