Dashboard list "table" pattern
The list on /workspace (and the signed-in master column elsewhere) is not an
HTML <table>. It's a CSS-grid responsive list wrapped in the nested-panel
card treatment. This is the canonical "table" to reuse for any sectioned,
scannable list of items (repos / PRs / issues / etc.).
Where it lives
| Piece | File |
|---|---|
| List shell + sections + row dispatch | apps/web/app/workspace/dashboard-list.tsx (DashboardList) |
| A single row (the grid) | apps/web/app/workspace/dashboard-row.tsx (Row) |
| Toolbar (tabs / search / new menu) | apps/web/app/workspace/dashboard-toolbar.tsx |
| Data shapes + filtering | apps/web/app/workspace/helpers.ts |
| Card surfaces | packages/ui/src/components/nested-panel.tsx (NestedPanel / NestedPanelCard) |
| Loading state | apps/web/app/workspace/dashboard-list-skeleton.tsx |
Anatomy
-
Outer frame (host layout):
m-2 … rounded-2xl p-0.5, then the list is centered withmx-auto … max-w-7xl. -
NestedPanel(outer): darker bordered shell (bg-background,#0B0A0Adark) holding the toolbar + inner card,gap-1between them. -
DashboardToolbar: tab row (all/ repos / pulls / issues) + search; tabs filter viafilterDashboardSections. -
NestedPanelCard(inner): lighter card (bg-card,#120F0Edark),@container,animate-list-in, scrolls. Keyed by active tab. -
Sections: flat siblings; each is a header (
title+ count) followed by its rows. Empty sections showemptyText. -
Row: aLinkrendered as a CSS grid with progressive lane reveal via container queries (title always wins as the column narrows, e.g. when the preview panel opens):- status / type icon lane (
1.25rem) - title (always)
- meta lane (
@lg) - signal lanes — checks / author avatar / visibility (
@2xl) - right-aligned relative "updated" date
Row extras: hover bg + active (
aria-current) state, and hover-intent prefetch/warm (useWarmOnHover) when inpreviewmode. - status / type icon lane (
How to reuse
import { DashboardList } from "@/app/workspace/dashboard-list"
import type { DashboardSection } from "@/app/workspace/helpers"
const sections: DashboardSection[] = [
{ kind: "repos", title: "Repositories", emptyText: "No repos yet.", rows: [/* DashboardRowData[] */] },
// kind ∈ "repos" | "pulls" | "issues" | "public" — drives which signal lanes show
]
<DashboardList sections={sections} newRepoHref="/repositories/new" preview />
DashboardRowData(seehelpers.ts) carriesid, href, title, meta, dateplus optionalstatus,checksStatus,authorUsername/DisplayName,visibility— each optional field lights up its corresponding lane.previewmakes rows open in the/workspace?preview=…detail panel instead of navigating.- To hand-roll the surfaces without the route-specific
DashboardList, useNestedPanel+NestedPanelCarddirectly (the exact class recipe is documented innested-panel.tsx).