Documentation Index
Fetch the complete documentation index at: https://grantmaster.dev/llms.txt
Use this file to discover all available pages before exploring further.
Surface System (Page Surface Primitives)
Goal
Unify page-surface UI the same way the modal refactor unified overlays. The surface system is the shared contract for:- section shells
- metric grids
- search and filter toolbars
- empty states
- page-body notices
- lightweight action cards
Naming note: These were originally prefixedWidget*but have been renamed toSurface*to avoid confusion with Dashboard Widgets (src/components/widgets/). The oldWidget*names are still exported as deprecated aliases for backward compatibility.
Shared Primitives
src/components/ui/widget-system.tsxSurfacePageHeaderSurfaceInsightListSurfaceSectionSurfaceMetricCardSurfaceMetricGridSurfaceToolbarSurfaceEmptyStateSurfaceNoticeSurfaceActionBarSurfaceActionCard
- Existing foundations reused under the hood:
src/components/ui/card.tsxsrc/components/ui/MetricCard.tsxsrc/components/ui/EmptyState.tsxsrc/components/ui/SearchFilterBar.tsxsrc/components/widgets/infowidgets/KpiCard.tsx
Conventions
Sections
- Use
SurfaceSectionfor titled page sections with optional description and top-right action. - Prefer one clear section title and one concise supporting sentence.
- Keep section actions short and task-oriented.
Metrics
- Use
SurfaceMetricGridfor dashboard or overview KPI strips. - Use the shared
iconprop when a metric needs a stable semantic cue; do not reintroduce local card markup just to render icons. - Use
MetricCard/KPI tone to communicate severity, not decorative color variation. - Only make metric cards clickable when they drill into a concrete filtered view.
Toolbars
- Use
SurfaceToolbarfor search + filters + actions + result-count surfaces. - Search belongs on the left; filters follow search; actions stay on the right.
- Result count and “Clear all” belong in the meta row beneath the controls.
Empty States
- Use
SurfaceEmptyStatefor zero-data and no-results states. - Title should explain the state directly.
- Description should explain what to do next.
- Include a primary action when the next step is obvious.
Notices
- Use
SurfaceNoticefor inline information, warnings, or critical operational banners inside a page body. - Prefer
SurfaceNoticeover hand-authored amber/rose/primary cards when the content is explanatory rather than tabular. - Use
tone="info" | "success" | "warning" | "danger"and keep the copy action-oriented.
Action Bars
- Use
SurfaceActionBarfor bulk-selection and short-lived operational rails that pair a status summary with immediate actions. - Keep the title stateful and concrete, for example
3 entries selected. - Prefer
SurfaceActionBarover bespoke full-width tinted bars when the content is primarily actions, not explanatory text.
Action Cards
- Use
SurfaceActionCardfor lightweight navigational or drill-in cards. - Keep title short and body descriptive.
- Reserve them for next-step navigation, not dense data display.
Initial Migrations
src/features/grantors/components/pages/grantors-page/ui.tsxThis file now delegates its reusable metric, toolbar, section, empty-state, and action-card surfaces to the shared widget system instead of defining a parallel local design language.src/components/ui/GrantOperatingSystem.tsxThe operating-page adapter now delegates page headers, KPI strips, and insight strips to the shared widget system so existing pages can inherit the unified surface language without immediate rewrites, and now exposesOperatingNoticeas the matching inline notice wrapper.src/features/users/components/UsersPage.tsxThe people overview now usesOperatingKpiStripfor its summary metrics instead of maintaining a localUserStatsCardgrid in two separate render paths.src/features/grantors/components/GrantorStatsWidget.tsxThe standalone grantor summary widget now usesSurfaceMetricGridinstead of bespoke metric card markup.src/features/projects/components/ProjectStatsWidget.tsxThe standalone project summary widget now usesSurfaceMetricGridinstead of bespoke metric card markup.src/features/projects/components/ProjectsToolbar.tsxProject search, filter, and action controls now sit onSurfaceToolbar.src/features/projects/components/ProjectsAllView.tsxThe main projects overview now usesSurfaceMetricGridandSurfaceEmptyStateinstead of a local KPI cluster and plain empty-state shell.src/features/projects/components/ProjectTemplateManager.tsxTemplate management now usesSurfaceEmptyStatefor the no-template path.src/features/projects/components/TemplateSelector.tsxTemplate picking now usesSurfaceEmptyStatefor the no-templates path.src/features/projects/components/ProjectsList.tsxThe list view now usesSurfaceEmptyStatefor the zero-results path.src/features/projects/components/ProjectsPageContent.tsxProject list fallback states now useSurfaceEmptyState, and dead local page-action scaffolding was removed.src/features/projects/components/project-editor/ProjectSettingsTab.tsxThe project-editor budget line surface now usesSurfaceSectionandSurfaceEmptyState.src/features/projects/components/project-details/tabs/ProjectSettingsTab.tsxThe project-details budget line surface now usesSurfaceSectionandSurfaceEmptyState.src/features/relations/components/pages/relations-page/RelationsEmptyState.tsxThe page-level no-data state now usesSurfaceEmptyState.src/features/extensions/components/ExtensionDetailPanel.tsxRepeated detail cards now useSurfaceMetricGrid,SurfaceSection, andSurfaceEmptyState.src/features/users/components/TrainingDashboard.tsxThe training dashboard summary strip, training-category metrics, and compliance fallback now useSurfaceMetricGrid,SurfaceSection, andSurfaceEmptyState.src/features/users/components/CapacityDashboard.tsxThe capacity dashboard pulse summary and inline operational notices now use the shared metric and notice primitives.src/features/users/components/ValuesManagement.tsxValues and behaviors now use the shared metric grid and empty-state shell for their overview and fallback surfaces.src/features/users/components/StaffAssignmentPlanner.tsxThe staffing planner summary, loading shell, and no-user fallback now use the shared widget primitives.src/features/users/components/CostAllocationDashboard.tsxCost allocation overview metrics, WNT warnings, WNT guidance, and no-data branches now use the shared widget primitives.src/features/users/components/time-off-planning/tabs/MyTimeOffTab.tsxTime-off balances, loading/error fallbacks, and the Arbodienst warning now use the shared widget primitives.src/components/TeamStatsWidget.tsxThe personnel summary widget now usesSurfaceMetricGrid.src/features/users/org-chart/components/OrgChartSummaryGrid.tsxThe org chart summary strip now usesSurfaceMetricGrid.src/features/users/org-chart/components/OrgChartDashboard.tsxThe org chart page now usesSurfaceEmptyStateandSurfaceNoticefor no-data and span-of-control guidance states.src/features/users/components/UserDocumentsDashboard.tsxDocument stats, type/compliance summaries, and the attention shell now use the shared widget primitives.src/features/grants/post-award/components/PostAwardTabContent.tsxPost-award overview metrics, zero states, and the report-deadline warning now use the shared widget primitives.src/components/PersonnelDirectory.tsxThe personnel directory summary strip, compliance warning chip, and no-results state now use the shared widget primitives.src/components/TimeOffManagement.tsxThe legacy time-off management surface now uses the shared widget primitives for leave balances, Arbodienst warnings, and loading/error empty states.src/components/TeamOversightDashboard.tsxThe team oversight dashboard now usesSurfaceMetricGrid,SurfaceToolbar, andSurfaceEmptyStateinstead of local KPI cards and a hand-built filter shell.src/components/manager/BulkJournalApproval.tsxBulk journal approval now uses the shared metric grid, empty state, and modal shell for the approval/rejection comment flow.src/components/security/SecurityAlertsPanel.tsxSecurity alerts now use the shared metric grid, empty state, and modal shell for event detail review.src/components/manager/BulkJournalApproval.tsxBulk journal review now usesSurfaceActionBarfor the selected-entry action rail instead of a bespoke tinted bulk-actions bar.src/features/notifications/components/NotificationHistory.tsxNotification bulk selection now usesSurfaceActionBarfor the selected-notification action rail.src/features/journals/components/pages/ManagerReviewDashboard.tsxManager review now usesSurfaceActionBarfor the selected-submission approval rail.src/features/users/components/users-page/UsersListView.tsxThe floating users bulk-selection control now usesSurfaceActionBarinstead of a custom dark pill treatment.src/features/users/components/department-structure/DepartmentStructure.tsxDepartment governance bulk actions now useSurfaceActionBarinstead of inline select-and-apply controls in the filter toolbar.src/features/users/components/department-structure/components/UsersAssignmentDialog.tsxThe department assignment dialog now usesSurfaceActionBarfor selection-state controls so select-all and selected-count behavior matches the shared action-rail language.src/features/admin/pages/AdminApprovalsPage.tsxThe approvals queue now usesSurfaceActionBarfor note, assignee, and bulk decision controls instead of a bespoke card-level action grid.src/features/grantors/components/GrantorAnalyticsTab.tsxGrantor analytics now usesSurfaceEmptyStateandSurfaceNoticefor its no-data and concentration-risk states.src/features/grantors/components/compliance-matrix/ComplianceConflictsBanner.tsxThe compliance conflicts banner now usesSurfaceNoticefor its shared warning shell while preserving the nested severity cards and dismiss action.src/features/projects/components/portfolio/PortfolioBudgetOverviewTab.tsxPortfolio budget notes now useSurfaceNoticeinstead of a bespoke amber informational card.src/features/projects/components/ProjectComplianceTab.tsxThe project compliance header, KPI strip, no-documents notice, and zero states now useSurfaceSection,SurfaceMetricGrid,SurfaceNotice, andSurfaceEmptyState.src/features/projects/components/ProjectPhaseManagement.tsxProject phase management now delegates to shared validation and modal building blocks instead of carrying bespoke inline dialog and requirements UI.src/features/projects/components/project-editor/ProjectTeamTab.tsxThe project-editor team tab now usesSurfaceNotice,SurfaceEmptyState, andSurfaceMetricGridfor its guidance, zero state, and summary strip.src/features/projects/components/project-details/tabs/ProjectTeamTab.tsxThe project-details team tab now uses the same shared notice, empty-state, and metric-grid surfaces as the editor flow.src/features/projects/components/phase-management/PhaseValidationResults.tsxPhase validation requirements now useSurfaceSectionplusSurfaceNoticecards for blockers, warnings, and success-ready states.src/features/projects/components/phase-management/PhaseAdvanceModal.tsxThe phase-advance flow now uses the sharedAppModal,ModalNotice, andModalFootercontract.src/features/projects/components/phase-management/PhaseArchiveModal.tsxThe phase-archive flow now uses the sharedAppModal,ModalNotice, andModalFootercontract.src/components/widgets/finance/BudgetModificationTrackerWidget.tsxBudget-modification approval and volatility alerts now useSurfaceNotice.src/components/widgets/finance/BurnRateComparisonWidget.tsxOverspend warnings and budget guidance now useSurfaceNotice.src/components/widgets/finance/CashFlowForecastWidget.tsxNegative-cash-flow and runway guidance banners now useSurfaceNotice.src/components/widgets/finance/SubcontractorSpendWidget.tsxThe subaward-threshold alert now usesSurfaceNotice.src/components/widgets/finance/GrantDiversificationWidget.tsxThe concentration-risk warning now usesSurfaceNoticewithout flattening the underlying HHI visualization.
Skeleton Loading States
Route-level code splitting needs meaningful Suspense fallbacks. The skeleton system provides purpose-built loading placeholders that match common page layouts.Components
| Component | File | Use Case |
|---|---|---|
AppShellSkeleton | src/components/ui/AppShellSkeleton.tsx | Full app shell wrapper (sidebar + header + content area) |
DashboardSkeleton | src/components/ui/skeletons/DashboardSkeleton.tsx | Dashboard pages with KPI cards and chart grids |
TablePageSkeleton | src/components/ui/skeletons/TablePageSkeleton.tsx | Data table pages with toolbar and rows |
FormPageSkeleton | src/components/ui/skeletons/FormPageSkeleton.tsx | Form-heavy pages with input fields |
WorkspaceSkeleton | src/components/ui/skeletons/WorkspaceSkeleton.tsx | Workspace/editor layouts with sidebar and main content |
ApprovalsSkeleton | src/components/ui/skeletons/ApprovalsSkeleton.tsx | Approval queue pages |
Usage
Use the appropriate skeleton as thefallback prop on React.Suspense boundaries wrapping lazy-loaded route components:
Guidelines
- Match the skeleton to the page pattern (dashboard, table, form, workspace)
- Use
AppShellSkeletononly for the top-level app shell boundary - Skeletons use Tailwind
animate-pulseonbg-slate-200 dark:bg-slate-700blocks
Grant Operating System Adapter
File:src/components/ui/GrantOperatingSystem.tsx
A domain-specific adapter layer that wraps Surface primitives with grant-lifecycle semantics. These components delegate to the shared Surface system rather than introducing independent primitives.
Components
| Component | Wraps | Purpose |
|---|---|---|
OperatingPageHeader | SurfacePageHeader | Page header with grant lifecycle context |
OperatingKpiStrip | SurfaceMetricGrid | KPI strip for grant operating metrics (budget utilization, compliance scores, etc.) |
OperatingInsightStrip | SurfaceInsightList | Contextual alerts/warnings tied to grant data (overdue reports, budget thresholds, etc.) |
OperatingNotice | SurfaceNotice | Inline operational notices with grant-specific tone mapping |
OperatingFilterBar | Custom card layout | Filter controls for grant operating views (stage, status, date range) |
LifecycleStageMap | — | Visual representation of grant lifecycle stages (stub — reserved for future implementation) |
Associated Types
Usage Pattern
Pages that consumeGrantOperatingSystem get centralized headers, KPI strips, and insight strips without maintaining local metric card markup:
Current Consumers
src/features/grants/discovery/components/GrantDiscoveryPage.tsx— KPI strip, insight strip, filter bar, lifecycle mapsrc/features/grants/post-award/components/PostAwardPage.tsx— KPI strip, insight stripsrc/features/users/components/UsersPage.tsx— KPI strip, insight strip
Next Recommended Wave
After this foundation batch, the highest-value next migrations are:- pages that already consume
GrantOperatingSystemThis gives you centralized headers/KPIs/insights without local rewrites. - remaining dashboard pages that still hand-roll KPI strips, notices, or empty states in the same file
These benefit most from
SurfaceMetricGrid,SurfaceSection, andSurfaceEmptyState. - remaining standalone search/filter shells
These should converge on
SurfaceToolbarrather than custom search bars. - repeated “detail panel” card stacks
These should converge on
SurfaceSectionand shared info-card patterns. - page-level template and list zero states in Projects and Grantors
These should converge on
SurfaceEmptyStateso list, template, and setup screens stop inventing their own fallback shells. - bespoke section headers and notice cards in operating pages
These should converge on
SurfaceSectionand a shared notice treatment so the page body matches the overlay and toolbar consistency work. - standalone legacy dashboards outside the Grantors, Grants, Projects, Users, and Extensions migration path These should migrate only when they are still using raw four-card grids or local warning shells rather than an existing centralized feature UI.
- visual regression coverage for the centralized page surfaces The widget layer now has enough reach that browser-level regression checks will catch real drift across multiple features.
- a broader repo
typecheckThe shared surface layer is now centralized enough that a wider compile check has real payoff, even if unrelated baseline issues still need triage. - selective cleanup of remaining explanatory finance/project notice cards Only convert panels that are actually notices; leave metric cards, gauges, badges, and data-viz-specific status treatments alone.