From 8749faae436630550b3542c35ad5ca090bdcd633 Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 2 Jul 2026 15:23:53 +0800 Subject: [PATCH] docs: add stage 1.8 shadcn ui standardization plan --- ...age-1-8-shadcn-admin-ui-standardization.md | 267 ++++++++++++++++++ ...-shadcn-admin-ui-standardization-design.md | 77 +++++ 2 files changed, 344 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-02-stage-1-8-shadcn-admin-ui-standardization.md create mode 100644 docs/superpowers/specs/2026-07-02-stage-1-8-shadcn-admin-ui-standardization-design.md diff --git a/docs/superpowers/plans/2026-07-02-stage-1-8-shadcn-admin-ui-standardization.md b/docs/superpowers/plans/2026-07-02-stage-1-8-shadcn-admin-ui-standardization.md new file mode 100644 index 0000000..657db3d --- /dev/null +++ b/docs/superpowers/plans/2026-07-02-stage-1-8-shadcn-admin-ui-standardization.md @@ -0,0 +1,267 @@ +# Stage 1.8 Shadcn Admin UI Standardization 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 UI foundation around shadcn/ui so future pages inherit a consistent enterprise admin layout, mobile navigation, form standard, select composition, and visual baseline. + +**Architecture:** shadcn/ui remains the source component library. Project `App*` components become thin composition wrappers around shadcn primitives, while feature pages consume those wrappers instead of hand-rolled layout. The first implementation batch fixes shell navigation, field primitives, select composition, and high-frequency forms. + +**Tech Stack:** React 19, Vite, TypeScript, Tailwind v3, shadcn/ui `radix-nova`, Radix primitives, lucide-react. + +--- + +## File Structure + +- Modify: `frontend/src/app/layout/AppShell.tsx` - passes mobile menu state into topbar/sidebar sheet. +- Modify: `frontend/src/components/app/AppSidebar.tsx` - extracts reusable navigation content and adds sheet-friendly rendering. +- Modify: `frontend/src/components/app/AppTopbar.tsx` - adds mobile menu button and keeps desktop actions. +- Create: `frontend/src/components/ui/field.tsx` - shadcn field primitive from CLI, merged without losing local component changes. +- Modify: `frontend/src/components/app/AppField.tsx` - thin wrapper over shadcn field primitives. +- Modify: `frontend/src/features/**` select call sites - wrap `SelectItem` with `SelectGroup`. +- Modify: `frontend/src/features/auth/LoginPage.tsx` - migrate login form fields. +- Modify: `frontend/src/features/tickets/TicketCreatePage.tsx` - migrate main create form fields. +- Modify: `frontend/src/features/solutions/SolutionCreatePage.tsx` - migrate solution form fields. +- Modify: `frontend/src/features/system/SystemUsersPage.tsx`, `SystemRolesPage.tsx`, `SystemUserGroupsPage.tsx` - migrate quick-create forms where practical. +- Test/verify: `npm run typecheck`, `npm run build`, grep scans, desktop/mobile browser checks. + +--- + +### Task 1: Mobile Shell Navigation + +**Files:** +- Modify: `frontend/src/app/layout/AppShell.tsx` +- Modify: `frontend/src/components/app/AppSidebar.tsx` +- Modify: `frontend/src/components/app/AppTopbar.tsx` + +- [ ] **Step 1: Inspect current shell boundaries** + +Run: + +```powershell +Get-Content frontend/src/app/layout/AppShell.tsx +Get-Content frontend/src/components/app/AppSidebar.tsx +Get-Content frontend/src/components/app/AppTopbar.tsx +``` + +Expected: `AppShell` renders fixed sidebar and topbar; sidebar is desktop-only. + +- [ ] **Step 2: Add mobile menu state in shell** + +Implement `mobileNavOpen` state in `AppShell`, pass `onMobileMenuClick` into topbar, and pass `mobileOpen/onMobileOpenChange` into sidebar. + +- [ ] **Step 3: Extract sidebar navigation content** + +In `AppSidebar`, extract grouped nav rendering into `SidebarNavContent({ onNavigate })`. Use the same component for desktop and mobile sheet. + +- [ ] **Step 4: Render mobile Sheet** + +Use existing shadcn `Sheet`, `SheetContent`, `SheetHeader`, and `SheetTitle`. The sheet title must be present for accessibility. Menu item clicks call `onNavigate`. + +- [ ] **Step 5: Add topbar mobile trigger** + +Add a `Button size="icon" variant="ghost"` visible below `lg`, with `Menu` icon using `data-icon` and `aria-label="打开导航"`. + +- [ ] **Step 6: Verify** + +Run: + +```powershell +npm run typecheck +``` + +Expected: exit code 0. + +--- + +### Task 2: Install and Merge Shadcn Field Primitive + +**Files:** +- Create: `frontend/src/components/ui/field.tsx` +- May modify: `frontend/src/components/ui/label.tsx` +- May modify: `frontend/src/components/ui/separator.tsx` +- Modify: `frontend/src/components/app/AppField.tsx` + +- [ ] **Step 1: Preview CLI changes** + +Run: + +```powershell +$env:NODE_USE_ENV_PROXY = "1"; $env:HTTP_PROXY = "http://127.0.0.1:7897"; $env:HTTPS_PROXY = "http://127.0.0.1:7897"; cd frontend; npx shadcn@latest add field --dry-run +``` + +Expected: creates `field.tsx`, previews updates to `label.tsx` and `separator.tsx`. + +- [ ] **Step 2: Inspect diffs before applying** + +Run: + +```powershell +$env:NODE_USE_ENV_PROXY = "1"; $env:HTTP_PROXY = "http://127.0.0.1:7897"; $env:HTTPS_PROXY = "http://127.0.0.1:7897"; cd frontend; npx shadcn@latest add field --diff field.tsx +$env:NODE_USE_ENV_PROXY = "1"; $env:HTTP_PROXY = "http://127.0.0.1:7897"; $env:HTTPS_PROXY = "http://127.0.0.1:7897"; cd frontend; npx shadcn@latest add field --diff label.tsx +$env:NODE_USE_ENV_PROXY = "1"; $env:HTTP_PROXY = "http://127.0.0.1:7897"; $env:HTTPS_PROXY = "http://127.0.0.1:7897"; cd frontend; npx shadcn@latest add field --diff separator.tsx +``` + +Expected: understand local changes before applying. + +- [ ] **Step 3: Add the field component** + +Apply the CLI result, then inspect changed files. If `label.tsx` or `separator.tsx` overwrite local customizations, restore needed local behavior manually. + +- [ ] **Step 4: Rebuild AppField** + +Make `AppField` render shadcn `Field`, `FieldLabel`, and optional `FieldDescription`. Support `htmlFor`, `required`, `invalid`, and `description` props. + +- [ ] **Step 5: Verify** + +Run: + +```powershell +npm run typecheck +``` + +Expected: exit code 0. + +--- + +### Task 3: Select Composition Sweep + +**Files:** +- Modify: `frontend/src/features/tickets/TicketFilterBar.tsx` +- Modify: `frontend/src/features/tickets/TicketCreatePage.tsx` +- Modify: `frontend/src/features/tickets/TicketComments.tsx` +- Modify: `frontend/src/features/solutions/SolutionListPage.tsx` +- Modify: `frontend/src/features/solutions/SolutionCreatePage.tsx` +- Modify: `frontend/src/features/design-system/DesignSystemPreview.tsx` + +- [ ] **Step 1: Add SelectGroup imports** + +For each file importing select primitives, add `SelectGroup`. + +- [ ] **Step 2: Wrap select items** + +Change: + +```tsx + + 全部状态 + +``` + +to: + +```tsx + + + 全部状态 + + +``` + +- [ ] **Step 3: Scan** + +Run: + +```powershell +rg "SelectContent>[\\s\\S]*SelectItem|\\s*\\s*