編輯式視覺重構(gòu):從語義 Token 到頁面級(jí)扁平化改造全指南)
即時(shí)通訊后端【免費(fèi)下載鏈接】WuKongIMMore than just IM 不只是即時(shí)通訊(IM)項(xiàng)目地址https://gitcode.com/gh_mirrors/wu/WuKongIM點(diǎn)擊查看免費(fèi)下載本文以倉庫內(nèi) docs/superpowers/plans/2026-07-07-web-editorial-console-redesign.md 實(shí)施計(jì)劃為骨架結(jié)合web/目錄下已落地的源碼與測試系統(tǒng)講解 WuKongIM 管理后臺(tái)webmanager UI向「白色編輯式控制臺(tái)editorial console」方向重構(gòu)的完整思路從全局語義 Token、扁平 App Shell到共享組件與cluster-monitor、nodes、plugins、login四個(gè)頁面的精修以及貫穿全程的測試驅(qū)動(dòng)TDD驗(yàn)證流程。讀完本文你將掌握一套只改視覺、不動(dòng)邏輯的前端重構(gòu)方法如何用 CSS 變量統(tǒng)一切換視覺語言、如何保持 API/路由/權(quán)限/i18n 語義不變地重排布局、如何用針對性測試斷言鎖定新視覺契約。重構(gòu)目標(biāo)與架構(gòu)原則WuKongIM 的 Web 管理端是一個(gè)面向集群運(yùn)維的控制臺(tái)operations cockpit。本次重構(gòu)的目標(biāo)是將其視覺語言切換到已評(píng)審?fù)ㄟ^的白色編輯式方向同時(shí)保留運(yùn)維信息密度operational density——即界面可以更報(bào)刊化、更克制但不能丟失一屏內(nèi)可讀的監(jiān)控信息量。架構(gòu)上采用三層遞進(jìn)策略先立全局語義 Token 與共享 Shell 組件讓絕大多數(shù)頁面自動(dòng)繼承新的視覺語言白色畫布、近黑主色、細(xì)發(fā)絲線邊框、收緊的圓角再做頁面級(jí)布局精修只對cluster-monitor集群監(jiān)控、nodes節(jié)點(diǎn)、plugins插件、login登錄四個(gè)頁面做針對性打磨嚴(yán)格保持行為不變API 行為、路由、權(quán)限、i18n 語義全部保持不變視覺變化一律通過現(xiàn)有 React 組件與 Tailwind class 表達(dá)。技術(shù)棧固定為Vite React 19 TypeScript Tailwind CSS v4 shadcn/radix primitives lucide-react Vitest Testing Library Bun與 web/package.json 中聲明的依賴一致React 19.2、Tailwind 4.2、Vitest 4.1、Bun 1.3.11。文件結(jié)構(gòu)總覽計(jì)劃將改動(dòng)收斂在以下文件上形成清晰的全局層 → 共享層 → 頁面層三層結(jié)構(gòu)層級(jí)文件全局樣式web/src/styles/globals.cssShell 布局web/src/app/layout/app-shell.tsx、topbar.tsx、sidebar-nav.tsx基礎(chǔ) UIweb/src/components/ui/button.tsx、card.tsxShell 組件web/src/components/shell/page-container.tsx、page-header.tsx、section-card.tsx、status-metric-card.tsx管理器組件web/src/components/manager/status-badge.tsx頁面web/src/pages/cluster-monitor/*、web/src/pages/nodes/page.tsx、web/src/pages/plugins/page.tsx、web/src/pages/login/page.tsx測試sidebar-nav.test.tsx、topbar.test.tsx、shell-components.test.tsx、login/page.test.tsx、cluster-monitor/page.test.tsx、nodes/page.test.tsx、plugins/page.test.tsx設(shè)計(jì)語言來源white editorial canvas本次調(diào)色板的靈感與依據(jù)來自 web/DESIGN.md一份Cohere 式設(shè)計(jì)系統(tǒng)分析白色編輯畫布是默認(rèn)表面深綠/深海軍藍(lán)只作為整幅產(chǎn)品條帶出現(xiàn)近黑主色#17171c承擔(dān)主 CTA 與深色區(qū)塊發(fā)絲線#d9d9dd承擔(dān)列表規(guī)則與區(qū)塊分隔陰影被壓制到最低層級(jí)靠表面交替 細(xì)邊框 圓角表達(dá)圓角從炫技的 30px 收緊到 8px/22px 兩級(jí)為主。DESIGN.md 中給出的關(guān)鍵 Dos 直接對應(yīng)本次改造動(dòng)作默認(rèn)使用白色畫布深色只作整幅產(chǎn)品條帶主 CTA 保持藥丸形pill與近黑填充大圖卡片使用 22px 圓角普通卡片 8px不要給卡片加厚重投影不要把每個(gè)區(qū)塊都做成卡片——編輯式界面大量使用無框行 規(guī)則線 開放空間。Task 1全局語義 Token 與扁平 Shell 基座第一步是重寫globals.css的明暗兩套 Token并讓 App Shell 去掉裝飾性元素。明色 Tokenweb/src/styles/globals.css的:root:root { --background: #ffffff; --foreground: #212121; --card: #ffffff; --card-foreground: #212121; --popover: #ffffff; --popover-foreground: #212121; --primary: #17171c; --primary-foreground: #ffffff; --secondary: #eeece7; --secondary-foreground: #212121; --muted: #f6f6f4; --muted-foreground: #616161; --accent: #edfce9; --accent-foreground: #003c33; --destructive: #b30000; --success: #167a42; --warning: #9b6516; --input: #d9d9dd; --border: #d9d9dd; --ring: #4c6ee6; --chart-1: #1863dc; --chart-2: #167a42; --chart-3: #9b6516; --chart-4: #b30000; --chart-5: #75758a; --status-healthy: #167a42; --status-running: #1863dc; --status-warning: #9b6516; --status-error: #b30000; --radius: 0.5rem; --sidebar: #ffffff; --sidebar-foreground: #212121; --sidebar-primary: #17171c; --sidebar-primary-foreground: #ffffff; --sidebar-accent: #f6f6f4; --sidebar-accent-foreground: #212121; --sidebar-border: #d9d9dd; --sidebar-ring: #4c6ee6; --top-section-active: #17171c; --top-section-active-foreground: #ffffff; font-family: Geist Variable, Inter, Arial, ui-sans-serif, system-ui, sans-serif; color: var(--foreground); background: var(--background); color-scheme: light; }要點(diǎn)--background白、--foreground墨色#212121、--primary近黑#17171c、--secondary暖石色#eeece7、--border/--input統(tǒng)一為發(fā)絲線#d9d9dd、焦點(diǎn)環(huán)--ring: #4c6ee6同時(shí)新增四組狀態(tài)語義色--status-healthy/running/warning/error供節(jié)點(diǎn)、監(jiān)控快照等狀態(tài)點(diǎn)使用與按鈕-成功-警示語義解耦。暗色 Token.dark.dark { --background: #071829; --foreground: #f7fafc; --card: #0b1f33; --card-foreground: #f7fafc; --popover: #0b1f33; --popover-foreground: #f7fafc; --primary: #ffffff; --primary-foreground: #17171c; --secondary: #112a3f; --secondary-foreground: #f7fafc; --muted: #102438; --muted-foreground: #b8c2cc; --accent: #003c33; --accent-foreground: #edfce9; --destructive: #ff8a7a; --success: #65d88a; --warning: #f5c76b; --input: #26394d; --border: #2c4054; --ring: #8fa2ff; --chart-1: #8fb7ff; --chart-2: #65d88a; --chart-3: #f5c76b; --chart-4: #ff8a7a; --chart-5: #b8c2cc; --status-healthy: #65d88a; --status-running: #8fb7ff; --status-warning: #f5c76b; --status-error: #ff8a7a; --sidebar: #071829; --sidebar-foreground: #f7fafc; --sidebar-primary: #ffffff; --sidebar-primary-foreground: #17171c; --sidebar-accent: #102438; --sidebar-accent-foreground: #f7fafc; --sidebar-border: #2c4054; --sidebar-ring: #8fa2ff; --top-section-active: #ffffff; --top-section-active-foreground: #17171c; color-scheme: dark; }暗色以深海軍藍(lán)#071829為畫布、#0b1f33為卡片面主色反轉(zhuǎn)為白、強(qiáng)調(diào)色取深綠#003c33。同時(shí)新增.top-section-link-active規(guī)則用--top-section-active/--top-section-active-foreground表達(dá)頂欄當(dāng)前分區(qū)高亮移除原實(shí)現(xiàn)中的 box-shadow 發(fā)光當(dāng)前 globals.css 已落地此規(guī)則。App Shell 扁平化web/src/app/layout/app-shell.tsxShell 從帶固定裝飾徑向光暈radial overlay的座艙塊變?yōu)榧兩馄娇蚣躤xport function AppShell() { return ( div classNamerelative flex h-screen flex-col overflow-hidden bg-background text-foreground Topbar / div classNamerelative flex min-h-0 flex-1 flex-col lg:flex-row SidebarNav / main classNamemin-h-0 min-w-0 flex-1 overflow-y-auto rolemain Outlet / /main /div /div ) }當(dāng)前倉庫的 app-shell.tsx 已落地為扁平結(jié)構(gòu)并額外保留了跳轉(zhuǎn)到主內(nèi)容的無障礙鏈接nav.skipToContent與移動(dòng)端導(dǎo)航狀態(tài)管理——這正是計(jì)劃強(qiáng)調(diào)的保持可訪問導(dǎo)航與認(rèn)證控制不變。測試驅(qū)動(dòng)先寫失敗斷言該計(jì)劃全程采用 TDD。Task 1 的第一步是強(qiáng)化web/src/app/layout/sidebar-nav.test.tsx中的殼層斷言test(keeps the primary menu outside the scrollable content area, async () { const router createMemoryRouter(routes, { initialEntries: [/dashboard] }) render( AppProviders RouterProvider router{router} / /AppProviders, ) const main await screen.findByRole(main) const contentFrame main.parentElement const appShell contentFrame?.parentElement expect(appShell).toHaveClass(h-screen, overflow-hidden) expect(contentFrame).toHaveClass(min-h-0, flex-1) expect(main).toHaveClass(min-h-0, overflow-y-auto) expect(screen.getByRole(navigation, { name: Primary navigation }).parentElement).toBe(contentFrame) expect(document.querySelector([class*radial-gradient])).not.toBeInTheDocument() })運(yùn)行聚焦測試驗(yàn)證先失敗、后通過cd web bun run test -- src/app/layout/sidebar-nav.test.tsx注意h-svh與h-screen的差異當(dāng)前源碼使用h-svh100svh計(jì)劃斷言使用h-screen這是實(shí)現(xiàn)細(xì)節(jié)層面的兼容取舍實(shí)際以通過測試為準(zhǔn)。Task 2編輯式 Topbar、Sidebar 與共享組件頂欄扁平化topbar.tsxTopbar 保持相同的組件邏輯認(rèn)證、主題、語言切換、集群健康徽章僅替換 JSX class 結(jié)構(gòu)去掉發(fā)光 logo/卡片化處理品牌標(biāo)記變?yōu)閟ize-7 rounded-sm border bg-foreground的方正小方塊data-brand-mark導(dǎo)航區(qū)改為border-l規(guī)則分隔的滾動(dòng)行右側(cè)保留盾牌健康徽章、主題/語言切換與登出按鈕header classNamesticky top-0 z-30 border-b border-border bg-background px-3 py-2 sm:px-4 rolebanner div classNameflex min-h-10 items-center justify-between gap-3 div classNameflex min-w-0 items-center gap-3 xl:gap-5 div classNameflex shrink-0 items-center gap-2 div aria-hidden classNamesize-7 rounded-sm border border-foreground bg-foreground dark:bg-primary >expect(screen.getByRole(banner)).toHaveClass(bg-background, border-b) expect(screen.getByRole(banner).querySelector([data-brand-mark])).toHaveClass(rounded-sm)當(dāng)前倉庫的 topbar.tsx 仍保留著舊式rounded-[10px] shadow-sm ring的品牌圖標(biāo)與backdrop-blur頂欄——說明該文件是重構(gòu)任務(wù)中尚未完成或正在分步進(jìn)行的部分恰好可以對照計(jì)劃中給出的目標(biāo)結(jié)構(gòu)來理解差距。側(cè)欄規(guī)則分隔sidebar-nav.tsxSidebar 從卡片堆疊的座艙塊改為規(guī)則線分隔的分區(qū)導(dǎo)航頂部是當(dāng)前分區(qū)的 mono 標(biāo)簽 品牌名 控制臺(tái)描述中部是當(dāng)前分區(qū)的導(dǎo)航項(xiàng)列表底部mt-auto border-t固定集群狀態(tài)摘要單節(jié)點(diǎn)集群就緒點(diǎn) CPU 靜態(tài)占位。計(jì)劃給出的核心結(jié)構(gòu)nav aria-labelPrimary navigation classNameflex w-full shrink-0 flex-col border-b border-sidebar-border bg-sidebar px-3 py-3 lg:w-[244px] lg:border-b-0 lg:border-r lg:px-4 lg:py-5 {/* 分區(qū)標(biāo)題 WuKongIM 描述 */} {/* NavLink 列表isActive 時(shí) bg-sidebar-primary */} div classNamemt-3 border-t border-sidebar-border pt-4 lg:mt-auto div classNamefont-mono text-[10px] font-semibold uppercase tracking-[0.22em] text-muted-foreground {intl.formatMessage({ id: shell.clusterStatus })} /div {/* 單節(jié)點(diǎn)集群 / Ready 狀態(tài)點(diǎn)、CPU / static */} /div /nav當(dāng)前 sidebar-nav.tsx 的桌面端NavigationContent已接近該目標(biāo)規(guī)則分隔、mt-auto狀態(tài)區(qū)、狀態(tài)點(diǎn)用--status-healthy同時(shí)保留了移動(dòng)端 Sheet 抽屜與主題/語言切換。共享組件批量替換Button藥丸化——web/src/components/ui/button.tsx的buttonVariants基礎(chǔ)類改為rounded-full藥丸variant 全面扁平化const buttonVariants cva( group/button inline-flex shrink-0 items-center justify-center rounded-full border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/35 ..., { variants: { variant: { default: bg-primary text-primary-foreground hover:bg-primary/90, outline: border-border bg-background text-foreground hover:bg-muted ..., secondary: bg-secondary text-secondary-foreground hover:bg-secondary/80 ..., ghost: border-transparent text-muted-foreground hover:bg-muted hover:text-foreground ..., destructive: border-destructive/25 bg-destructive/8 text-destructive hover:bg-destructive/12 ..., link: h-auto rounded-none border-transparent px-0 text-primary underline-offset-4 hover:underline, }, size: { default: h-9 gap-1.5 px-4 ..., xs: h-6 gap-1 px-2 text-xs ..., sm: h-8 gap-1.5 px-3 text-[0.8rem] ..., lg: h-10 gap-1.5 px-5 ..., icon: size-8 p-0, icon-xs: size-6 p-0 ..., icon-sm: size-7 p-0, icon-lg: size-9 p-0, }, }, defaultVariants: { variant: default, size: default }, } )當(dāng)前 button.tsx 已完全落地此結(jié)構(gòu)。Card收緊圓角、去陰影感——web/src/components/ui/card.tsx的 Card 基類從rounded-3xl級(jí)別的卡片改為group/card flex flex-col gap-4 overflow-hidden rounded-lg border border-border bg-card py-4 text-sm text-card-foreground has-data-[slotcard-footer]:pb-0 has-[img:first-child]:pt-0>return ( section className{cn(border-b border-border bg-background pb-4, className)} div classNameflex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between div classNamespace-y-2 {eyebrow ? HeaderEyebrow{eyebrow}/HeaderEyebrow : null} {!eyebrow inRouter ? RouteEyebrow / : null} h1 classNametext-4xl font-normal leading-none tracking-normal text-foreground sm:text-5xl{title}/h1 p classNamemax-w-3xl text-sm leading-6 text-muted-foreground{description}/p /div {actions ? div classNameflex flex-wrap items-center gap-2{actions}/div : null} /div {children ? div classNamemt-4 border-t border-border pt-4{children}/div : null} /section )當(dāng)前 page-header.tsx 已落地對應(yīng)測試斷言const header screen.getByRole(heading, { name: Dashboard }).closest(section) expect(header).toHaveClass(border-b, bg-background) expect(header).not.toHaveClass(rounded-3xl) expect(screen.getByText(Scope: single-node cluster).parentElement).toHaveClass(border-t)SectionCard扁平區(qū)塊容器——web/src/components/shell/section-card.tsx改為shadow-none 8px 圓角 頂部規(guī)則頭Card id{id} className{cn(border border-border bg-card shadow-none, className)} CardHeader classNameborder-b border-border bg-background py-3 CardTitle classNamefont-mono text-xs font-semibold uppercase tracking-[0.14em] text-foreground{title}/CardTitle {description ? CardDescription classNameleading-6{description}/CardDescription : null} {action ? CardAction{action}/CardAction : null} /CardHeader CardContent classNamept-4{children}/CardContent /Card當(dāng)前 section-card.tsx 已落地。StatusMetricCard編輯式數(shù)據(jù)單元格——web/src/components/shell/status-metric-card.tsx將指標(biāo)卡對齊為編輯式數(shù)據(jù)單元mono 數(shù)字 狀態(tài)點(diǎn) 可選描述SectionCard classNamemin-h-28 title{label} div classNameflex items-start justify-between gap-3 div classNamefont-mono text-3xl font-medium tabular-nums text-foreground{value}/div StatusDot tone{tone} / /div {description ? p classNamemt-2 text-xs text-muted-foreground{description}/p : null} /SectionCardStatusBadge語義小徽章——web/src/components/manager/status-badge.tsx保持小型語義徽章填充/邊框?qū)R新調(diào)色板success/8、warning/8、destructive/8的低飽和填充 25%~30% 透明度邊框span className{cn( inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium capitalize, variant success border-success/25 bg-success/8 text-success, variant warning border-warning/25 bg-warning/8 text-warning, variant danger border-destructive/30 bg-destructive/8 text-destructive, variant neutral border-border bg-background text-muted-foreground, )} >cd web bun run test -- src/app/layout/topbar.test.tsx src/app/layout/sidebar-nav.test.tsx src/components/shell/shell-components.test.tsxTask 3Cluster Monitor 工作臺(tái)精修集群監(jiān)控頁保持?jǐn)?shù)據(jù)流完全不變只換 Shell 間距與表面。當(dāng)前 cluster-monitor-toolbar.tsx 已落地data-monitor-toolbartrue包裝 section 變?yōu)橐?guī)則底行cluster-monitor-snapshot-strip.tsx 已將快照卡片改為cluster-monitor-snapshot-cell鍵值格。工具欄規(guī)則化section classNameflex flex-col gap-3 border-b border-border bg-background pb-4 lg:flex-row lg:items-center lg:justify-between >div classNameborder-b border-border px-1 py-3 sm:px-3 >// cluster-monitor-card-grid.tsx section classNamegrid gap-3 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 // cluster-monitor-metric-card.tsx article classNameflex min-h-[320px] flex-col rounded-lg border border-border bg-card p-4 shadow-none統(tǒng)計(jì)單元格改為min-w-0 rounded-md border border-border bg-background px-2 py-2圖表高度保持h-[120px]不變防止重繪引發(fā)的回歸。頁面測試新增視覺角色斷言不斷言脆弱的完整 class 串expect(screen.getByRole(heading, { name: /live monitor/i }).closest(section)).toHaveClass(border-b) expect(screen.getByLabelText(/category/i).closest(section)).toHaveAttribute(data-monitor-toolbar, true) expect(screen.getAllByTestId(cluster-monitor-snapshot-cell).length).toBeGreaterThan(0) expect(screen.getAllByTestId(cluster-monitor-metric-card)[0]).toHaveClass(shadow-none)運(yùn)行cd web bun run test -- src/pages/cluster-monitor/page.test.tsxTask 4Nodes 列表的編輯式密度節(jié)點(diǎn)頁保持節(jié)點(diǎn) API 與全部生命周期動(dòng)作不變激活、onboard、slot 遷出、scale-in 各階段、移除、提升 Controller voter、查看配置等均來自 manager-api.ts只做布局精修。新增NodeSummaryCellweb/src/pages/nodes/page.tsxfunction NodeSummaryCell({ label, value }: { label: string; value: number | string }) { return ( div classNameborder-b border-border px-1 py-3 sm:px-3 div classNametext-xs text-muted-foreground{label}/div div classNamemt-1 font-mono text-2xl font-medium tabular-nums text-foreground{value}/div /div ) }摘要條用nodes-summary-strip測試錨點(diǎn)承載六項(xiàng)指標(biāo)——總數(shù)、存活、不健康、draining、可調(diào)度、Controller voter 數(shù)div classNamegrid gap-0 border-y border-border sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6 >expect(screen.getByTestId(nodes-summary-strip)).toBeInTheDocument() expect(screen.getByRole(table, { name: /nodes/i })).toHaveClass(w-full)運(yùn)行cd web bun run test -- src/pages/nodes/page.test.tsxTask 5Plugins 庫存與綁定面分離插件頁在視覺上把插件清單inventory與綁定關(guān)系bindings兩塊表面清晰分離行/表單全部扁平化同時(shí)保持全部動(dòng)作 handler、對話框狀態(tài)、配置解析與 API 調(diào)用不變。摘要條plugins-summary-strip改為緊湊單元格div classNamegrid gap-0 border-y border-border sm:grid-cols-2 xl:grid-cols-4 >function SummaryPill({ label }: { label: string }) { return ( div classNameborder-b border-border px-1 py-3 text-sm text-foreground sm:px-3 {label} /div ) }可訪問名稱清單表aria-label{plugins.inventory.title}綁定表單aria-label{plugins.bindings.title}。當(dāng)前 plugins/page.tsx 已落地摘要條與兩處 aria-label。表面扁平化兩張插件表的容器統(tǒng)一overflow-x-auto border border-border表頭border-b bg-background text-xs uppercase tracking-[0.14em]行border-t border-border align-top hover:bg-muted/45。測試斷言expect(screen.getByTestId(plugins-summary-strip)).toBeInTheDocument() expect(screen.getByRole(table, { name: /plugin inventory/i })).toHaveClass(w-full) expect(screen.getByRole(form, { name: /plugin bindings/i })).toBeInTheDocument()運(yùn)行cd web bun run test -- src/pages/plugins/page.test.tsxTask 6Login 品牌面板登錄頁移除裝飾光暈重排雙欄表面。計(jì)劃目標(biāo)結(jié)構(gòu)外層main為min-h-screen overflow-hidden bg-background去掉 fixed radial overlay左欄品牌區(qū)max-w-2xl品牌標(biāo)記改為方正size-9 rounded-sm border border-foreground bg-foreground在能力證明 chips 之后新增緊湊品牌帶login-brand-bandrounded-[22px] bg-[var(--primary)] p-6 text-primary-foreground內(nèi)含 mono 眉標(biāo)auth.operationsCockpit與單節(jié)點(diǎn)集群就緒文案表單卡login-form-cardrounded-[22px] border border-border bg-card p-6 shadow-none sm:p-8輸入框統(tǒng)一rounded-md border border-input bg-background px-3 py-2.5focus 用border-ring ring-2 ring-ring/30錯(cuò)誤塊rounded-md border-destructive/25 bg-destructive/8 text-destructive。測試斷言expect(screen.getByTestId(login-brand-band)).toHaveClass(bg-[var(--primary)]) expect(screen.getByTestId(login-form-card)).toHaveClass(rounded-[22px]) expect(document.querySelector([class*radial-gradient])).not.toBeInTheDocument()運(yùn)行cd web bun run test -- src/pages/login/page.test.tsx當(dāng)前倉庫的 login/page.tsx 已移除 radial-gradient僅保留低對比圓形裝飾線雙欄預(yù)覽區(qū)與表單面板的登錄/登出、訪客賬號(hào)提示、密碼可見切換、錯(cuò)誤提示等交互邏輯完整保留——表單卡與輸入框的圓角/邊框仍在舊風(fēng)格rounded-xl、rounded-[28px]容器屬于待按計(jì)劃收尾的部分。Task 7最終驗(yàn)證與構(gòu)建清理所有任務(wù)完成后按固定順序執(zhí)行驗(yàn)證流水線# 1. 布局與 Shell 聚焦測試 cd web bun run test -- src/app/layout/sidebar-nav.test.tsx src/app/layout/topbar.test.tsx src/components/shell/shell-components.test.tsx # 2. 頁面聚焦測試 cd web bun run test -- src/pages/login/page.test.tsx src/pages/cluster-monitor/page.test.tsx src/pages/nodes/page.test.tsx src/pages/plugins/page.test.tsx # 3. TypeScript 檢查期望退出碼 0 cd web bunx tsc -b # 4. 生產(chǎn)構(gòu)建期望退出碼 0產(chǎn)出 Vite build cd web bun run build # 5. 空白/生成物檢查 git diff --check git status --short若git diff --check非 0或web/dist/index.html等哈希型構(gòu)建產(chǎn)物被誤改用非破壞性定向 checkout 還原生成物僅限構(gòu)建產(chǎn)物不動(dòng)無關(guān)用戶文件git restore web/dist/index.html若第 1~5 步要求源碼修復(fù)則統(tǒng)一提交git add web/src web/package.json web/bun.lock git commit -m style(web): complete editorial console verificationSelf-Review 檢查清單計(jì)劃自帶的自檢項(xiàng)也可作為任何視覺重構(gòu)的驗(yàn)收模板Spec 覆蓋全局 token 與扁平 shellTask 1-2、共享 UI/shell 組件Task 2、集群監(jiān)控工作臺(tái)Task 3、節(jié)點(diǎn)列表密度Task 4、插件庫存與綁定分離Task 5、登錄品牌面板Task 6、聚焦測試 TS 構(gòu)建 diff 清理Task 7占位符掃描無 blocked 標(biāo)記詞無含糊的 add tests 步驟每個(gè)任務(wù)都含精確文件、具體改動(dòng)、精確命令與預(yù)期結(jié)果類型與行為一致性保留現(xiàn)有組件名、路由行為、API 函數(shù)、auth store 用法、i18n id 與頁面級(jí)數(shù)據(jù)流測試錨點(diǎn)最小化新增 test id 僅限視覺/結(jié)構(gòu)性地標(biāo)——nodes-summary-strip、plugins-summary-strip、login-brand-band、login-form-card、cluster-monitor-snapshot-cell不向業(yè)務(wù)邏輯注入測試專屬標(biāo)記。結(jié)語倉庫現(xiàn)狀與落地進(jìn)度對照對照當(dāng)前倉庫源碼本計(jì)劃的各模塊落地進(jìn)度如下均為源碼事實(shí)可直接打開對應(yīng)文件驗(yàn)證已落地globals.css明暗 token含狀態(tài)語義色與.top-section-link-active、app-shell.tsx 扁平殼、button.tsx 藥丸按鈕、card.tsx 收緊圓角、page-header.tsx 開放頁眉、section-card.tsx 與 status-metric-card.tsx 扁平化、cluster-monitor-toolbar.tsx 與 cluster-monitor-snapshot-strip.tsx、nodes/page.tsx 摘要條與扁平表格、plugins/page.tsx 摘要條與 aria-label待收尾topbar.tsx的品牌標(biāo)記與頂欄樣式、login/page.tsx的表單卡與輸入框圓角仍為舊風(fēng)格——對照計(jì)劃中的目標(biāo) JSX 即可明確差異。這套重構(gòu)方法論的核心價(jià)值在于視覺語言由語義 Token 驅(qū)動(dòng)、行為契約由聚焦測試鎖定——先鋪 Token 讓全站自動(dòng)換膚再逐頁精修并把視覺目標(biāo)寫成斷言最后用tsc -b與生產(chǎn)構(gòu)建兜底。任何以只改外觀、不動(dòng)邏輯為目標(biāo)的控制臺(tái)/后臺(tái)重構(gòu)都可以復(fù)用這份任務(wù)劃分與驗(yàn)證流水線。贊分享即時(shí)通訊后端【免費(fèi)下載鏈接】WuKongIMMore than just IM 不只是即時(shí)通訊(IM)項(xiàng)目地址https://gitcode.com/gh_mirrors/wu/WuKongIM點(diǎn)擊查看免費(fèi)下載相關(guān)推薦WuKongIM 分布式后臺(tái)管理 UI 的 Pencil 設(shè)計(jì)實(shí)現(xiàn)方案從視覺 Token 到七頁面巡檢工作臺(tái)WuKongIM 分布式后臺(tái)管理 UI 的 Pencil 設(shè)計(jì)實(shí)現(xiàn)方案從視覺 Token 到七頁面巡檢工作臺(tái) WuKongIM 的分布式后臺(tái)管理界面需要一套以即時(shí)通訊后端WuKongIM Web 管理控制臺(tái)與 Manager API 集成實(shí)戰(zhàn)從契約到頁面的完整實(shí)施路徑WuKongIM Web 管理控制臺(tái)與 Manager API 集成實(shí)戰(zhàn)從契約到頁面的完整實(shí)施路徑 導(dǎo)讀 本文以 WuKongIM 倉庫中的實(shí)施計(jì)劃 docs即時(shí)通訊后端DeepSeek-Coder-V2開源代碼智能模型的革命性突破與企業(yè)級(jí)應(yīng)用指南DeepSeek Coder V2開源代碼智能模型的革命性突破與企業(yè)級(jí)應(yīng)用指南 在當(dāng)今快速發(fā)展的AI編程輔助領(lǐng)域開源模型正在以前所未有的速度追趕甚至超越閉源人工智能大模型基礎(chǔ)模型代碼模型上一篇貓抓網(wǎng)頁資源嗅探完整指南網(wǎng)頁視頻捕獲、批量下載與 M3U8 合并下一篇三步配好字幕實(shí)時(shí)翻譯PotPlayer 調(diào)用百度翻譯讓外語字幕變中文創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考