From c0bccbbaf29fc71434a86f2ced5db59fc1c9714d Mon Sep 17 00:00:00 2001 From: Huarch Date: Wed, 16 Sep 2026 15:51:42 +0800 Subject: [PATCH] feat(ui): complete drainage workbench style migration --- .../ACRYLIC_DESIGN_INVENTORY.md | 0 docs/status-language.md | 40 + package.json | 3 +- pnpm-lock.yaml | 8 + src/app/app.e2e.ts | 8 +- src/app/app.tsx | 2 +- .../agent/components/agent-collapsed-rail.tsx | 10 +- .../agent/components/agent-command-panel.tsx | 548 ++++++++---- .../agent/components/agent-history-panel.tsx | 135 +-- .../components/agent-message-details.test.tsx | 90 ++ .../components/agent-message-details.tsx | 314 ++++--- src/features/agent/components/agent-motion.ts | 2 - .../components/agent-operational-brief.tsx | 106 ++- .../agent/components/agent-persona.tsx | 2 +- .../components/agent-ui-envelope-renderer.tsx | 7 +- .../components/streaming-token-response.tsx | 4 +- src/features/agent/hooks/use-agent-voice.ts | 2 - src/features/agent/index.ts | 50 +- src/features/agent/message-state.test.ts | 27 + src/features/agent/message-state.ts | 19 + src/features/agent/session-state.test.ts | 27 + src/features/agent/session-state.ts | 23 +- src/features/agent/types.ts | 2 + .../agent/ui-envelope/map-actions.test.ts | 42 +- src/features/agent/ui-envelope/map-actions.ts | 50 +- .../map/core/components/annotation-panel.tsx | 2 +- .../core/components/base-layers-control.tsx | 4 +- .../map/core/components/control-panel.tsx | 6 +- .../map/core/components/draw-toolbar.tsx | 15 +- .../map/core/components/layer-control.tsx | 2 +- .../map/core/components/layer-panel.tsx | 4 +- src/features/map/core/components/legend.tsx | 5 +- .../map/core/components/map-control-styles.ts | 4 +- .../map/core/components/measure-panel.tsx | 4 +- .../map/core/components/notice-actions.tsx | 6 +- .../core/components/notice-presentation.tsx | 97 +-- src/features/map/core/components/notice.tsx | 4 +- .../map/core/components/scale-line.tsx | 4 +- src/features/map/core/components/toolbar.tsx | 17 +- src/features/map/core/components/zoom.tsx | 15 +- src/features/map/core/index.ts | 62 ++ .../components/agent-task-ticker.tsx | 19 +- .../components/condition-report-risk.ts | 2 +- .../components/feature-insight-panel.tsx | 151 +--- .../workbench/components/feature-popover.tsx | 8 +- .../components/feature-property-list.tsx | 2 +- .../workbench/components/map-dev-panel.tsx | 4 +- .../mobile-workbench-sheet-layout.ts | 17 + .../components/mobile-workbench-sheet.test.ts | 16 + .../components/mobile-workbench-sheet.tsx | 198 +++++ .../scheduled-condition-detail-panel.tsx | 199 ++--- .../scheduled-condition-feed-utils.test.ts | 42 + .../scheduled-condition-feed-utils.ts | 96 ++- .../components/scheduled-condition-feed.tsx | 304 +++++-- .../workbench/components/toolbar-panel.tsx | 23 +- .../components/workbench-agent-panels.tsx | 84 ++ .../components/workbench-top-bar-menus.tsx | 95 +- .../components/workbench-top-bar-styles.ts | 13 +- .../components/workbench-top-bar.tsx | 107 ++- .../workbench/data/running-workflows.ts | 2 +- .../data/scheduled-conditions.test.ts | 12 + .../workbench/data/scheduled-conditions.ts | 13 +- .../hooks/agent-session-message-state.ts | 18 +- .../workbench/hooks/use-agent-panel-resize.ts | 120 +++ .../workbench/hooks/use-map-interactions.ts | 5 +- .../hooks/use-simulation-layer-visibility.ts | 2 - .../workbench/hooks/use-workbench-agent.ts | 85 +- .../workbench/hooks/use-workbench-drawing.ts | 2 - .../hooks/use-workbench-map-controller.ts | 36 +- .../workbench/hooks/use-workbench-map.ts | 2 - .../hooks/use-workbench-measurement.ts | 2 - .../hooks/use-workbench-runtime-data.test.ts | 15 + .../hooks/use-workbench-runtime-data.ts | 71 ++ src/features/workbench/index.ts | 3 +- .../workbench/layout/workbench-layout.test.ts | 74 +- .../workbench/layout/workbench-layout.ts | 84 +- src/features/workbench/map-workbench-page.tsx | 504 +++++------ src/features/workbench/map/camera.test.ts | 4 +- .../workbench/map/geoserver-config.ts} | 7 +- .../workbench/map/map-control-config.ts | 18 +- .../workbench/map/map-feature-query.ts | 2 +- src/features/workbench/map/sources.ts | 2 +- src/features/workbench/map/toolbar-config.ts | 2 +- src/features/workbench/types.ts | 12 +- .../utils/scheduled-condition-alerts.ts | 36 + .../utils/scheduled-condition-prompts.ts | 7 +- src/lib/utils.ts | 6 - src/shared/ai-elements/agent.tsx | 4 +- src/shared/ai-elements/code-block.tsx | 4 +- src/shared/ai-elements/conversation.tsx | 4 +- src/shared/ai-elements/message.tsx | 4 +- src/shared/ai-elements/persona.tsx | 2 +- src/shared/ai-elements/plan.tsx | 4 +- src/shared/ai-elements/prompt-input.tsx | 4 +- src/shared/ai-elements/shimmer.tsx | 4 +- src/shared/ai-elements/suggestion.tsx | 4 +- src/shared/ui/accordion.tsx | 4 +- src/shared/ui/badge.tsx | 2 +- src/shared/ui/button-group.tsx | 2 +- src/shared/ui/button-interaction.ts | 20 + src/shared/ui/button.test.tsx | 83 ++ src/shared/ui/button.tsx | 99 ++- src/shared/ui/card.tsx | 2 +- src/shared/ui/collapsible.tsx | 2 - src/shared/ui/command.tsx | 4 +- src/shared/ui/dialog.tsx | 4 +- src/shared/ui/dropdown-menu.tsx | 4 +- src/shared/ui/hover-card.tsx | 4 +- src/shared/ui/input-group.tsx | 12 +- src/shared/ui/input.tsx | 2 +- src/shared/ui/select.tsx | 4 +- src/shared/ui/separator.tsx | 4 +- src/shared/ui/spinner.tsx | 2 +- src/shared/ui/status.test.tsx | 54 ++ src/shared/ui/status.tsx | 126 +++ src/shared/ui/textarea.tsx | 2 +- src/shared/ui/tooltip.tsx | 4 +- src/styles.css | 808 ++++++++++++++---- src/test/module-boundaries.test.ts | 51 ++ src/test/status-language.test.ts | 100 +++ tests/browser/agent-acrylic.e2e.ts | 9 +- tests/browser/agent-panel-resize.e2e.ts | 16 +- tests/browser/agent-question.e2e.ts | 160 ++++ .../browser/agent-streaming-stability.e2e.ts | 37 +- tests/browser/button-system.e2e.ts | 172 ++++ tests/browser/mobile-workbench-sheet.e2e.ts | 161 ++++ tests/browser/scrollbar-system.e2e.ts | 92 ++ .../workbench-panel-map-stability.e2e.ts | 34 + tests/browser/workbench-visual.e2e.ts | 301 +++++++ ...workbench-desktop-light-chromium-linux.png | Bin 0 -> 375958 bytes ...bench-desktop-satellite-chromium-linux.png | Bin 0 -> 465735 bytes ...-desktop-wide-max-agent-chromium-linux.png | Bin 0 -> 632207 bytes ...ench-mobile-agent-light-chromium-linux.png | Bin 0 -> 116909 bytes ...ile-condition-satellite-chromium-linux.png | Bin 0 -> 93975 bytes ...h-mobile-launcher-light-chromium-linux.png | Bin 0 -> 71928 bytes 135 files changed, 4919 insertions(+), 1794 deletions(-) rename ACRYLIC_DESIGN_INVENTORY.md => docs/ACRYLIC_DESIGN_INVENTORY.md (100%) create mode 100644 docs/status-language.md create mode 100644 src/features/agent/components/agent-message-details.test.tsx create mode 100644 src/features/agent/message-state.test.ts create mode 100644 src/features/agent/message-state.ts create mode 100644 src/features/map/core/index.ts create mode 100644 src/features/workbench/components/mobile-workbench-sheet-layout.ts create mode 100644 src/features/workbench/components/mobile-workbench-sheet.test.ts create mode 100644 src/features/workbench/components/mobile-workbench-sheet.tsx create mode 100644 src/features/workbench/components/scheduled-condition-feed-utils.test.ts create mode 100644 src/features/workbench/components/workbench-agent-panels.tsx create mode 100644 src/features/workbench/hooks/use-agent-panel-resize.ts create mode 100644 src/features/workbench/hooks/use-workbench-runtime-data.test.ts create mode 100644 src/features/workbench/hooks/use-workbench-runtime-data.ts rename src/{lib/config.ts => features/workbench/map/geoserver-config.ts} (50%) create mode 100644 src/features/workbench/utils/scheduled-condition-alerts.ts delete mode 100644 src/lib/utils.ts create mode 100644 src/shared/ui/button-interaction.ts create mode 100644 src/shared/ui/button.test.tsx create mode 100644 src/shared/ui/status.test.tsx create mode 100644 src/shared/ui/status.tsx create mode 100644 src/test/module-boundaries.test.ts create mode 100644 src/test/status-language.test.ts create mode 100644 tests/browser/agent-question.e2e.ts create mode 100644 tests/browser/button-system.e2e.ts create mode 100644 tests/browser/mobile-workbench-sheet.e2e.ts create mode 100644 tests/browser/scrollbar-system.e2e.ts create mode 100644 tests/browser/workbench-panel-map-stability.e2e.ts create mode 100644 tests/browser/workbench-visual.e2e.ts create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-desktop-light-chromium-linux.png create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-desktop-satellite-chromium-linux.png create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-desktop-wide-max-agent-chromium-linux.png create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-mobile-agent-light-chromium-linux.png create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-mobile-condition-satellite-chromium-linux.png create mode 100644 tests/browser/workbench-visual.e2e.ts-snapshots/workbench-mobile-launcher-light-chromium-linux.png diff --git a/ACRYLIC_DESIGN_INVENTORY.md b/docs/ACRYLIC_DESIGN_INVENTORY.md similarity index 100% rename from ACRYLIC_DESIGN_INVENTORY.md rename to docs/ACRYLIC_DESIGN_INVENTORY.md diff --git a/docs/status-language.md b/docs/status-language.md new file mode 100644 index 0000000..42903c4 --- /dev/null +++ b/docs/status-language.md @@ -0,0 +1,40 @@ +# 状态语言 + +系统使用五种语义状态。业务模块保留自己的领域枚举,并在展示边界映射到共享 +`StatusTone`,不要让展示文案、接口字符串或 Tailwind 原色类直接决定状态样式。 + +| Tone | 用途 | 典型状态 | +| --- | --- | --- | +| `neutral` | 尚未开始或不再活动 | 预约、草案、待办、取消、中止、跳过、未分级 | +| `info` | 正在发生的过程 | 执行中、提交中、加载中、连接中 | +| `success` | 已完成或健康 | 完成、在线、正常、已批准 | +| `warning` | 需要关注但未达到异常 | 关注、降级、待复核、待复令、待确认 | +| `danger` | 已异常或操作失败 | 异常、失败、离线、高风险、事故、权限拒绝 | + +## 报告风险 + +报告风险固定为三档: + +- `normal` 映射 `success`,显示“正常”。 +- `attention` 映射 `warning`,显示“关注”。 +- `critical` 映射 `danger`,显示“异常”。 + +`info` 只表示过程,不参与风险等级。不得把 `attention` 合并到正常或异常。 + +## 表达规则 + +- 状态标签使用 `StatusBadge`,小型指示使用 `StatusDot`,图标节点使用 `StatusIcon`。 +- 大面积容器只使用柔和背景,禁止实心红色或橙色状态卡片。 +- `warning` 和 `danger` 必须同时提供文字或图标,不能只依赖颜色。 +- 只有进行中的状态可以使用 `live` 或 `loading` 动效。 +- “复令”是提交处置结果的动作,执行完成但尚未提交时显示“待复令”,使用静态 + `warning`;不得继续显示为“执行中”或提前显示为完成态。 +- 动效必须在 `prefers-reduced-motion` 下停止。 +- 蓝色选中态属于交互反馈,不作为业务风险状态。 +- 紫色只表示 Agent 身份,不表示未知或更高风险。 + +## 地图状态 + +地图与面板共享语义,但保留独立色值以适应浅色底图、影像底图和白色 casing。 +新增地图状态时,应先补充 `map-colors.ts`,再通过对比度测试验证,不要在图层定义中 +写入新的颜色字面量。 diff --git a/package.json b/package.json index 6a7dc11..522fea6 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@deck.gl/core": "^9.3.7", "@deck.gl/layers": "^9.3.7", "@deck.gl/mapbox": "^9.3.7", + "@fontsource-variable/noto-sans-sc": "^5.3.0", "@radix-ui/react-accordion": "^1.2.14", "@radix-ui/react-collapsible": "^1.1.14", "@radix-ui/react-dialog": "^1.1.17", @@ -72,10 +73,10 @@ "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "@vitejs/plugin-react-swc": "^4.0.2", + "esbuild": "^0.28.0", "eslint": "^9.17.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.16", - "esbuild": "^0.28.0", "globals": "^15.14.0", "jsdom": "^25.0.1", "msw": "^2.6.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f0fe7df..c1523ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: '@deck.gl/mapbox': specifier: ^9.3.7 version: 9.3.7(@deck.gl/core@9.3.7)(@luma.gl/core@9.3.6)(@math.gl/web-mercator@4.1.0) + '@fontsource-variable/noto-sans-sc': + specifier: ^5.3.0 + version: 5.3.0 '@radix-ui/react-accordion': specifier: ^1.2.14 version: 1.2.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -681,6 +684,9 @@ packages: '@floating-ui/utils@0.2.12': resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} + '@fontsource-variable/noto-sans-sc@5.3.0': + resolution: {integrity: sha512-lNar1dF7Ik/lHNPo/7JWG0TolXY29LtsqYgMvEysooZ5bsO9uH4shJmRrwyJ3PjyTPljhpMJEK0jDuLSU4vJ1w==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -4671,6 +4677,8 @@ snapshots: '@floating-ui/utils@0.2.12': {} + '@fontsource-variable/noto-sans-sc@5.3.0': {} + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 diff --git a/src/app/app.e2e.ts b/src/app/app.e2e.ts index c621b74..d1f634e 100644 --- a/src/app/app.e2e.ts +++ b/src/app/app.e2e.ts @@ -82,7 +82,7 @@ test("preserves compact typography in header and agent controls", async ({ page await expect(approvalControl).toHaveCSS("font-size", "12px"); await expect(approvalControl).toHaveCSS("line-height", "16px"); await expect(suggestion).toHaveCSS("font-size", "12px"); - await expect(suggestion).toHaveCSS("font-weight", "500"); + await expect(suggestion).toHaveCSS("font-weight", "600"); }); test("lets interactive utilities override surface materials", async ({ page }) => { @@ -102,7 +102,7 @@ test("lets interactive utilities override surface materials", async ({ page }) = expect(hoverBackground).not.toBe(restingBackground); }); -test("preserves v3 menu and panel styling through Tailwind v4", async ({ page }) => { +test("keeps menu origin and integrated composer styling through Tailwind v4", async ({ page }) => { await page.setViewportSize({ width: 1440, height: 900 }); await page.goto("/"); @@ -118,6 +118,6 @@ test("preserves v3 menu and panel styling through Tailwind v4", async ({ page }) const commandShadow = await agentCommandControl.evaluate( (element) => window.getComputedStyle(element).boxShadow ); - expect(commandShadow).toContain("rgba(0, 0, 0, 0.05) 0px 1px 2px 0px"); - expect(commandShadow).not.toContain("0px 1px 3px 0px"); + expect(commandShadow).toBe("none"); + await expect(agentCommandControl).toHaveCSS("border-top-width", "0px"); }); diff --git a/src/app/app.tsx b/src/app/app.tsx index 64985c2..609e42e 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -1,4 +1,4 @@ -import { MapToaster } from "@/features/map/core/components/notice"; +import { MapToaster } from "@/features/map/core"; import { MapWorkbenchPage } from "@/features/workbench"; import { AppProviders } from "./providers"; diff --git a/src/features/agent/components/agent-collapsed-rail.tsx b/src/features/agent/components/agent-collapsed-rail.tsx index b06774a..f3d3a99 100644 --- a/src/features/agent/components/agent-collapsed-rail.tsx +++ b/src/features/agent/components/agent-collapsed-rail.tsx @@ -1,9 +1,6 @@ -"use client"; - import { ChevronRight } from "lucide-react"; import type { PersonaState } from "@/shared/ai-elements/persona"; -import { cn } from "@/lib/utils"; -import { MAP_MAJOR_PANEL_RADIUS_CLASS_NAME } from "@/features/map/core/components/map-control-styles"; +import { cn } from "@/shared/ui/cn"; import { AgentPersona } from "./agent-persona"; type AgentCollapsedRailProps = { @@ -23,8 +20,7 @@ export function AgentCollapsedRail({