docs: add shadcn ui rewrite implementation plan

This commit is contained in:
afei A
2026-03-28 00:07:26 +08:00
parent 24a7543e91
commit ded6555dbc

View File

@@ -0,0 +1,459 @@
# Auto Virtual Tryon Admin Frontend Shadcn Rewrite Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Rebuild the frontend admin UI around a denser shadcn-style console shell, a clearer review workflow, and real high-density list pages for orders and workflows.
**Architecture:** Keep the existing App Router routes, BFF handlers, adapters, and backend contracts intact while replacing the card-heavy presentation layer with shared shell, toolbar, and table primitives. Migrate in layers: first the dashboard shell and reusable UI primitives, then the review flow, then the orders and workflows list pages, so each step lands on top of a stable layout system instead of reworking page code twice.
**Tech Stack:** Next.js App Router, React, TypeScript, Tailwind CSS v4, Vitest, React Testing Library, jsdom, Lucide React
---
### Task 1: Rebuild The Shared Dashboard Shell
**Files:**
- Modify: `src/components/layout/dashboard-shell.tsx`
- Modify: `src/components/layout/nav-config.ts`
- Modify: `src/components/ui/page-header.tsx`
- Modify: `app/globals.css`
- Test: `tests/ui/dashboard-shell.test.tsx`
- [ ] **Step 1: Write the failing shell-density tests**
```tsx
test("uses a narrow rail and full-width desktop shell", () => {
render(<DashboardShell>content</DashboardShell>);
expect(screen.getByLabelText("Dashboard rail").className).toContain(
"md:w-[228px]",
);
expect(screen.getByLabelText("Dashboard content").className).toContain(
"md:overflow-y-auto",
);
});
```
- [ ] **Step 2: Run the shell test to confirm it fails**
Run: `npm run test -- tests/ui/dashboard-shell.test.tsx`
Expected: FAIL because the existing shell still uses the wide `280px` rail, large radii, and old container classes
- [ ] **Step 3: Rewrite the shell layout to use a thinner rail and full-width main area**
```tsx
<div className="min-h-screen bg-[var(--app-bg)] text-[var(--ink)] md:h-screen md:overflow-hidden">
<div className="grid h-full md:grid-cols-[228px_minmax(0,1fr)]">
<aside className="border-r border-[var(--shell-border)] bg-[var(--shell)] md:h-full" />
<main className="min-h-0 md:h-full md:overflow-y-auto" />
</div>
</div>
```
- [ ] **Step 4: Tighten the shared header spacing and typography**
```tsx
<header className="flex items-start justify-between gap-4 border-b border-[var(--border-soft)] pb-4">
<div className="space-y-1">
<p className="font-[var(--font-mono)] text-[11px] uppercase tracking-[0.24em]">
{eyebrow}
</p>
<h1 className="text-2xl font-semibold tracking-[-0.03em]">{title}</h1>
</div>
</header>
```
- [ ] **Step 5: Update shell variables and density tokens in global CSS**
```css
:root {
--page-gap: 16px;
--panel-radius: 14px;
--control-height: 38px;
}
```
- [ ] **Step 6: Re-run the shell test**
Run: `npm run test -- tests/ui/dashboard-shell.test.tsx`
Expected: PASS
- [ ] **Step 7: Commit the shell rewrite**
```bash
git add src/components/layout/dashboard-shell.tsx src/components/layout/nav-config.ts src/components/ui/page-header.tsx app/globals.css tests/ui/dashboard-shell.test.tsx
git commit -m "feat: tighten dashboard shell density"
```
### Task 2: Add Shared Dense Console Primitives
**Files:**
- Create: `src/components/ui/input.tsx`
- Create: `src/components/ui/select.tsx`
- Create: `src/components/ui/table.tsx`
- Create: `src/components/ui/separator.tsx`
- Create: `src/components/ui/page-toolbar.tsx`
- Create: `src/components/ui/metric-chip.tsx`
- Modify: `src/components/ui/button.tsx`
- Modify: `src/components/ui/card.tsx`
- Modify: `src/components/ui/status-badge.tsx`
- Test: `tests/ui/status-badge.test.tsx`
- Create: `tests/ui/page-toolbar.test.tsx`
- [ ] **Step 1: Write failing tests for compact toolbar and compact badge behavior**
```tsx
test("renders a dense toolbar row with compact controls", () => {
render(
<PageToolbar>
<Input aria-label="search" />
<Select aria-label="status" />
</PageToolbar>,
);
expect(screen.getByLabelText("search").className).toContain("h-9");
});
```
- [ ] **Step 2: Run the toolbar and badge tests to confirm they fail**
Run: `npm run test -- tests/ui/page-toolbar.test.tsx tests/ui/status-badge.test.tsx`
Expected: FAIL because the new primitives do not exist yet and current badge sizing is larger than the dense target
- [ ] **Step 3: Implement the shared compact primitives**
```tsx
export function PageToolbar({ children }: PropsWithChildren) {
return (
<div className="flex flex-wrap items-center gap-3 border-b border-[var(--border-soft)] pb-4">
{children}
</div>
);
}
```
- [ ] **Step 4: Normalize button, card, and status badge sizes to the new density**
```tsx
const buttonVariants = {
default: "h-9 rounded-md px-3 text-sm",
secondary: "h-9 rounded-md px-3 text-sm",
};
```
- [ ] **Step 5: Re-run the toolbar and badge tests**
Run: `npm run test -- tests/ui/page-toolbar.test.tsx tests/ui/status-badge.test.tsx`
Expected: PASS
- [ ] **Step 6: Commit the shared primitives**
```bash
git add src/components/ui tests/ui
git commit -m "feat: add dense console ui primitives"
```
### Task 3: Rewrite The Review Queue Page As A High-Density Table
**Files:**
- Modify: `src/features/reviews/review-workbench-list.tsx`
- Modify: `src/features/reviews/components/review-queue.tsx`
- Create: `src/features/reviews/components/review-filters.tsx`
- Modify: `app/(dashboard)/reviews/workbench/page.tsx`
- Test: `tests/features/reviews/review-workbench-list.test.tsx`
- [ ] **Step 1: Replace the current list-page expectations with queue-table expectations**
```tsx
test("renders a compact review queue table with triage columns", async () => {
render(<ReviewWorkbenchListScreen />);
expect(await screen.findByRole("columnheader", { name: "订单号" })).toBeInTheDocument();
expect(screen.getByRole("columnheader", { name: "修订状态" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "刷新队列" })).toBeInTheDocument();
});
```
- [ ] **Step 2: Run the review queue test to confirm it fails**
Run: `npm run test -- tests/features/reviews/review-workbench-list.test.tsx`
Expected: FAIL because the current page still renders the old prose-heavy layout instead of the table and compact toolbar
- [ ] **Step 3: Add a compact filter row for query, status, revision state, and refresh**
```tsx
<PageToolbar>
<Input aria-label="审核关键词搜索" />
<Select aria-label="审核状态筛选" />
<Select aria-label="修订状态筛选" />
<Button variant="secondary"></Button>
</PageToolbar>
```
- [ ] **Step 4: Rebuild the queue body as a compact table**
```tsx
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead>workflowId</TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
</Table>
```
- [ ] **Step 5: Re-run the review queue test**
Run: `npm run test -- tests/features/reviews/review-workbench-list.test.tsx`
Expected: PASS
- [ ] **Step 6: Commit the queue rewrite**
```bash
git add src/features/reviews app/\(dashboard\)/reviews/workbench/page.tsx tests/features/reviews/review-workbench-list.test.tsx
git commit -m "feat: rewrite review queue as dense table"
```
### Task 4: Rewrite The Review Detail Page As A Decision Surface
**Files:**
- Modify: `src/features/reviews/review-workbench-detail.tsx`
- Modify: `src/features/reviews/components/review-action-panel.tsx`
- Modify: `src/features/reviews/components/review-image-panel.tsx`
- Modify: `src/features/reviews/components/review-revision-panel.tsx`
- Modify: `src/features/reviews/components/review-workflow-summary.tsx`
- Modify: `app/(dashboard)/reviews/workbench/[orderId]/page.tsx`
- Test: `tests/features/reviews/review-workbench-detail.test.tsx`
- [ ] **Step 1: Rewrite the detail-page tests around sticky summary and two-column decision layout**
```tsx
test("keeps the decision actions visible next to the image workspace", async () => {
render(<ReviewWorkbenchDetailScreen orderId={101} />);
expect(await screen.findByText("返回审核列表")).toBeInTheDocument();
expect(screen.getByText("审核动作")).toBeInTheDocument();
expect(screen.getByText("人工修订")).toBeInTheDocument();
});
```
- [ ] **Step 2: Run the review detail test to confirm it fails**
Run: `npm run test -- tests/features/reviews/review-workbench-detail.test.tsx`
Expected: FAIL because the current detail page still renders the old header and stacked module layout
- [ ] **Step 3: Add the sticky summary bar and two-column page frame**
```tsx
<div className="sticky top-0 z-10 border-b border-[var(--border-soft)] bg-[var(--surface)]/95 backdrop-blur">
<div className="flex items-center justify-between gap-4 py-3">
<Button variant="secondary" asChild>
<Link href="/reviews/workbench"></Link>
</Button>
</div>
</div>
```
- [ ] **Step 4: Collapse workflow timeline content into a compact summary block and keep primary actions grouped**
```tsx
<Tabs defaultValue="audit">
<TabsList>
<TabsTrigger value="audit"></TabsTrigger>
<TabsTrigger value="revision"></TabsTrigger>
</TabsList>
</Tabs>
```
- [ ] **Step 5: Re-run the review detail test**
Run: `npm run test -- tests/features/reviews/review-workbench-detail.test.tsx`
Expected: PASS
- [ ] **Step 6: Commit the review detail rewrite**
```bash
git add src/features/reviews app/\(dashboard\)/reviews/workbench/\[orderId\]/page.tsx tests/features/reviews/review-workbench-detail.test.tsx
git commit -m "feat: rebuild review detail decision surface"
```
### Task 5: Rewrite Orders As A Real Dense List Page
**Files:**
- Modify: `src/features/orders/orders-home.tsx`
- Create: `src/features/orders/components/orders-toolbar.tsx`
- Create: `src/features/orders/components/orders-table.tsx`
- Modify: `app/(dashboard)/orders/page.tsx`
- Test: `tests/features/orders/orders-home.test.tsx`
- [ ] **Step 1: Replace the current orders-home expectations with dense-table expectations**
```tsx
test("renders orders as a high-density table with shared toolbar controls", async () => {
render(<OrdersHome recentOrders={[order]} />);
expect(screen.getByRole("columnheader", { name: "订单号" })).toBeInTheDocument();
expect(screen.getByRole("columnheader", { name: "服务模式" })).toBeInTheDocument();
expect(screen.getByLabelText("订单状态筛选")).toBeInTheDocument();
});
```
- [ ] **Step 2: Run the orders-home test to confirm it fails**
Run: `npm run test -- tests/features/orders/orders-home.test.tsx`
Expected: FAIL because the current page still renders direct-lookup and recent-visits cards rather than a dense list table
- [ ] **Step 3: Extract the compact toolbar with keyword, status, service mode, and pagination controls**
```tsx
<OrdersToolbar
query={selectedQuery}
status={selectedStatus}
onQuerySubmit={onQuerySubmit}
onStatusChange={onStatusChange}
onPageChange={onPageChange}
/>
```
- [ ] **Step 4: Replace the card list with a real orders table and compact row actions**
```tsx
<OrdersTable
items={recentOrders}
onOpenOrder={onOpenOrder}
onOpenWorkflow={onOpenWorkflow}
/>
```
- [ ] **Step 5: Re-run the orders-home test**
Run: `npm run test -- tests/features/orders/orders-home.test.tsx`
Expected: PASS
- [ ] **Step 6: Commit the orders page rewrite**
```bash
git add src/features/orders app/\(dashboard\)/orders/page.tsx tests/features/orders/orders-home.test.tsx
git commit -m "feat: rewrite orders page as dense list"
```
### Task 6: Rewrite Workflows As A Real Dense List Page
**Files:**
- Modify: `src/features/workflows/workflow-lookup.tsx`
- Create: `src/features/workflows/components/workflow-toolbar.tsx`
- Create: `src/features/workflows/components/workflow-table.tsx`
- Modify: `app/(dashboard)/workflows/page.tsx`
- Test: `tests/features/workflows/workflow-lookup.test.tsx`
- [ ] **Step 1: Replace the current workflow-page expectations with dense-table expectations**
```tsx
test("renders workflows as a high-density table with shared toolbar controls", async () => {
render(<WorkflowLookup items={[workflow]} />);
expect(screen.getByRole("columnheader", { name: "流程类型" })).toBeInTheDocument();
expect(screen.getByRole("columnheader", { name: "失败次数" })).toBeInTheDocument();
expect(screen.getByLabelText("流程状态筛选")).toBeInTheDocument();
});
```
- [ ] **Step 2: Run the workflow-page test to confirm it fails**
Run: `npm run test -- tests/features/workflows/workflow-lookup.test.tsx`
Expected: FAIL because the current page still renders direct-lookup and placeholder index cards rather than a dense table
- [ ] **Step 3: Extract the compact workflow toolbar**
```tsx
<WorkflowToolbar
query={selectedQuery}
status={selectedStatus}
onQuerySubmit={onQuerySubmit}
onStatusChange={onStatusChange}
onPageChange={onPageChange}
/>
```
- [ ] **Step 4: Replace the workflow card list with a diagnostic table**
```tsx
<WorkflowTable items={items} onOpenWorkflow={onOpenWorkflow} />
```
- [ ] **Step 5: Re-run the workflow-page test**
Run: `npm run test -- tests/features/workflows/workflow-lookup.test.tsx`
Expected: PASS
- [ ] **Step 6: Commit the workflows page rewrite**
```bash
git add src/features/workflows app/\(dashboard\)/workflows/page.tsx tests/features/workflows/workflow-lookup.test.tsx
git commit -m "feat: rewrite workflows page as dense list"
```
### Task 7: Clean Up Old Oversized Patterns And Verify The Whole Rewrite
**Files:**
- Modify: `src/features/orders/components/order-summary-card.tsx`
- Modify: `src/features/orders/components/order-workflow-card.tsx`
- Modify: `src/features/workflows/components/workflow-status-card.tsx`
- Modify: `src/features/workflows/components/workflow-timeline.tsx`
- Modify: `README.md`
- Test: `tests/features/orders/order-detail.test.tsx`
- Test: `tests/features/workflows/workflow-detail.test.tsx`
- [ ] **Step 1: Write or adjust any failing detail-page tests caused by the density-system changes**
```tsx
test("keeps order detail summaries compact under the new density rules", () => {
render(<OrderDetailScreen orderId={101} />);
expect(screen.getByText("订单摘要")).toBeInTheDocument();
});
```
- [ ] **Step 2: Run the affected detail tests to confirm what regressed**
Run: `npm run test -- tests/features/orders/order-detail.test.tsx tests/features/workflows/workflow-detail.test.tsx`
Expected: FAIL only if the shared primitive changes require updated structure or copy assertions
- [ ] **Step 3: Remove any leftover oversized radii, padding, and stacked-card patterns from detail support components**
```tsx
<section className="rounded-[14px] border border-[var(--border-soft)] bg-[var(--surface)] p-4">
...
</section>
```
- [ ] **Step 4: Update the README to mention the shadcn-style dense console direction**
```md
- shared admin shell uses compact toolbar and table patterns
- review, orders, and workflows pages are optimized for desktop operator density
```
- [ ] **Step 5: Run full verification**
Run: `npm run verify`
Expected: PASS with all Vitest suites green, ESLint green, TypeScript green, and `next build` green
- [ ] **Step 6: Run a browser smoke test on the three main surfaces**
Run: `npm run dev`
Expected: desktop manual check confirms wider shell, denser lists, and clearer review flow on `/orders`, `/reviews/workbench`, `/workflows`
- [ ] **Step 7: Commit the cleanup and verification pass**
```bash
git add src/features/orders/components src/features/workflows/components README.md
git commit -m "refactor: align detail views with dense console ui"
```