From f4318a9b9cd3465078d131cc736ff2b0efd5c180 Mon Sep 17 00:00:00 2001 From: Huarch Date: Tue, 28 Jul 2026 16:39:36 +0800 Subject: [PATCH] feat: refine workbench visuals and map controls Unify the Agent history extension with the header acrylic surface, preserve the full conversation body, and consolidate shared control and status styling. Restore map flow and SCADA controller behavior, remove obsolete rendering paths, and extend regression coverage. Button press coverage now releases outside the target so state assertions cannot accidentally toggle the control. --- AGENTS.md | 4 +- README.md | 4 +- docs/status-language.md | 40 + index.html | 8 +- package.json | 6 +- pnpm-lock.yaml | 375 +--------- src/app/app.e2e.ts | 8 +- .../agent/components/agent-collapsed-rail.tsx | 2 +- .../agent/components/agent-command-panel.tsx | 506 ++++++++----- .../agent/components/agent-history-panel.tsx | 129 ++-- .../components/agent-message-details.tsx | 236 +++--- .../components/agent-operational-brief.tsx | 104 +-- .../components/agent-ui-envelope-renderer.tsx | 3 +- src/features/agent/index.ts | 2 + src/features/agent/message-state.test.ts | 27 + src/features/agent/message-state.ts | 19 + src/features/agent/types.ts | 2 + .../map/core/components/control-panel.tsx | 4 +- .../map/core/components/draw-toolbar.tsx | 11 +- .../map/core/components/layer-panel.tsx | 2 +- src/features/map/core/components/legend.tsx | 3 +- .../map/core/components/map-control-styles.ts | 4 +- .../map/core/components/measure-panel.tsx | 2 +- .../map/core/components/notice-actions.tsx | 2 +- .../core/components/notice-presentation.tsx | 81 +- src/features/map/core/components/notice.tsx | 2 +- src/features/map/core/components/toolbar.tsx | 13 +- src/features/map/core/components/zoom.tsx | 11 +- .../components/agent-task-ticker.tsx | 13 +- .../components/feature-insight-panel.tsx | 4 +- .../workbench/components/feature-popover.tsx | 41 +- .../components/map-dev-panel.test.tsx | 104 +++ .../workbench/components/map-dev-panel.tsx | 691 ++++++++++++++++-- .../components/mobile-workbench-sheet.tsx | 2 +- .../scheduled-condition-detail-panel.tsx | 207 +++--- .../scheduled-condition-feed-utils.test.ts | 42 ++ .../scheduled-condition-feed-utils.ts | 67 +- .../components/scheduled-condition-feed.tsx | 82 ++- .../components/workbench-agent-panels.tsx | 17 +- .../components/workbench-top-bar-menus.tsx | 89 ++- .../components/workbench-top-bar-styles.ts | 13 +- .../components/workbench-top-bar.tsx | 34 +- .../data/scheduled-conditions.test.ts | 17 + .../workbench/data/scheduled-conditions.ts | 2 +- .../workbench/hooks/use-agent-panel-resize.ts | 75 +- .../workbench/hooks/use-workbench-agent.ts | 49 +- .../workbench/hooks/use-workbench-map.ts | 95 ++- src/features/workbench/index.ts | 5 + .../workbench/layout/workbench-layout.test.ts | 23 +- .../workbench/layout/workbench-layout.ts | 62 +- src/features/workbench/map-workbench-page.tsx | 6 +- .../workbench/map/annotation-layers.ts | 8 +- src/features/workbench/map/camera.test.ts | 6 +- .../workbench/map/color-contrast.test.ts | 31 +- .../workbench/map/flow-overlay.test.ts | 182 ++++- src/features/workbench/map/flow-overlay.ts | 482 ++++++++++-- .../workbench/map/flow-path-extension.ts | 34 - .../workbench/map/layer-group-style.ts | 21 +- src/features/workbench/map/map-colors.ts | 33 +- .../workbench/map/map-feature-query.test.ts | 8 +- .../workbench/map/map-feature-query.ts | 6 +- .../workbench/map/scada-analysis.test.ts | 15 +- src/features/workbench/map/scada-analysis.ts | 17 +- src/features/workbench/map/sources.ts | 38 +- .../workbench/map/value-label.test.ts | 12 +- src/features/workbench/map/value-label.ts | 167 ++++- .../map/workbench-map-controller.test.ts | 244 ++++++- .../workbench/map/workbench-map-controller.ts | 292 ++++++-- src/shared/ui/button-interaction.ts | 20 + src/shared/ui/button.test.tsx | 83 +++ src/shared/ui/button.tsx | 97 ++- src/shared/ui/input-group.tsx | 8 +- src/shared/ui/status.test.tsx | 54 ++ src/shared/ui/status.tsx | 126 ++++ src/styles.css | 655 +++++++++++++---- src/test/status-language.test.ts | 100 +++ tests/browser/agent-acrylic.e2e.ts | 451 +++++++++++- tests/browser/agent-panel-resize.e2e.ts | 34 +- .../browser/agent-streaming-stability.e2e.ts | 189 ++++- tests/browser/agent-voice-hydration.e2e.ts | 2 +- tests/browser/button-system.e2e.ts | 172 +++++ tests/browser/map-dev-panel.e2e.ts | 59 +- tests/browser/map-notice-position.e2e.ts | 2 +- tests/browser/mobile-workbench-sheet.e2e.ts | 16 +- .../scheduled-condition-acrylic.e2e.ts | 173 ++++- tests/browser/scrollbar-system.e2e.ts | 92 +++ .../workbench-panel-map-stability.e2e.ts | 2 +- tests/browser/workbench-top-bar-mobile.e2e.ts | 30 +- tests/browser/workbench-visual.e2e.ts | 41 +- ...workbench-desktop-light-chromium-linux.png | Bin 480892 -> 511367 bytes ...bench-desktop-satellite-chromium-linux.png | Bin 439364 -> 431179 bytes ...-desktop-wide-max-agent-chromium-linux.png | Bin 873795 -> 847605 bytes ...ench-mobile-agent-light-chromium-linux.png | Bin 144415 -> 118055 bytes ...ile-condition-satellite-chromium-linux.png | Bin 98550 -> 99524 bytes ...h-mobile-launcher-light-chromium-linux.png | Bin 72242 -> 72461 bytes vite.config.ts | 3 + 96 files changed, 5480 insertions(+), 1875 deletions(-) create mode 100644 docs/status-language.md create mode 100644 src/features/agent/message-state.test.ts create mode 100644 src/features/agent/message-state.ts create mode 100644 src/features/workbench/components/map-dev-panel.test.tsx create mode 100644 src/features/workbench/components/scheduled-condition-feed-utils.test.ts delete mode 100644 src/features/workbench/map/flow-path-extension.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/status-language.test.ts create mode 100644 tests/browser/button-system.e2e.ts create mode 100644 tests/browser/scrollbar-system.e2e.ts diff --git a/AGENTS.md b/AGENTS.md index 6c0ed0d..5262625 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,8 +4,8 @@ This repository contains the Vite and React single-page frontend for the Agent-driven supply-network WebGIS. Runtime TypeScript lives under `src/`. -The application uses React 19, TypeScript, Tailwind CSS, MapLibre GL, deck.gl, -SWR, Vitest, and Playwright. +The application uses React 19, TypeScript, Tailwind CSS, MapLibre GL, SWR, +Vitest, and Playwright. Keep this project browser-first. Do not add Next.js APIs, `"use client"` directives, or general backend-for-frontend routes. Agent reasoning and tool diff --git a/README.md b/README.md index 06e58ff..d6afd80 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Next TJWater 是供水管网 WebGIS Agent 工作台的前端项目。界面以地图为主视图,集成供水管网图层、调度状态、事件处置、Agent 对话和受控前端动作。 -项目使用 Vite、React 19、TypeScript 和 Tailwind CSS 4。地图基于 MapLibre GL,流向效果使用 deck.gl,Agent 消息支持代码高亮、数学公式和 Mermaid 图表。 +项目使用 Vite、React 19、TypeScript 和 Tailwind CSS 4。地图与流向效果基于 MapLibre GL,Agent 消息支持代码高亮、数学公式和 Mermaid 图表。 ## 主要功能 @@ -87,4 +87,4 @@ src/ ## 构建说明 -生产构建可能提示 deck.gl 和 luma.gl 的第三方循环分块,以及 Shiki、Mermaid 语言包超过 Rollup 默认的 500 kB 阈值。当前构建和浏览器测试可以正常完成,这些提示不影响产物生成。 +生产构建可能提示 Shiki、Mermaid 语言包超过 Rollup 默认的 500 kB 阈值。当前构建和浏览器测试可以正常完成,这些提示不影响产物生成。 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/index.html b/index.html index ac492c5..1be7703 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,13 @@ - TJWater WebGIS Agent + + 供水管网
diff --git a/package.json b/package.json index 9a28d69..6484e37 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,6 @@ }, "dependencies": { "@ai-sdk/react": "^4.0.9", - "@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", @@ -73,14 +70,13 @@ "@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", - "playwright": "^1.61.1", "prettier": "^3.4.2", "tailwindcss": "^4.1.17", "tw-animate-css": "^1.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 344dda0..345db01 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,15 +11,6 @@ importers: '@ai-sdk/react': specifier: ^4.0.9 version: 4.0.34(react@19.2.7)(zod@3.25.76) - '@deck.gl/core': - specifier: ^9.3.7 - version: 9.3.7 - '@deck.gl/layers': - specifier: ^9.3.7 - version: 9.3.7(@deck.gl/core@9.3.7)(@loaders.gl/core@4.4.3)(@luma.gl/core@9.3.6)(@luma.gl/engine@9.3.6(@luma.gl/core@9.3.6)(@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6))) - '@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 @@ -192,9 +183,6 @@ importers: msw: specifier: ^2.6.8 version: 2.15.0(@types/node@24.13.3)(typescript@7.0.2) - playwright: - specifier: ^1.61.1 - version: 1.61.1 prettier: specifier: ^3.4.2 version: 3.9.5 @@ -457,24 +445,6 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@deck.gl/core@9.3.7': - resolution: {integrity: sha512-l+YPm1I0Fwj+b7xsu8FvyDT5MGPgEPJe2cQJUpQNgG742b2goB4tyYpteUhNAOeVo1gmenvqv36ZJGNsGxipJA==} - - '@deck.gl/layers@9.3.7': - resolution: {integrity: sha512-T2CnkEU1QEqmusrSdot7+8Nl09gzntG5DvhaogyBbTjmABhTh4rUnS6dLOjf5/ju3aJ+Q58/FvDzgBBcK4V7kg==} - peerDependencies: - '@deck.gl/core': ~9.3.0 - '@loaders.gl/core': ^4.4.3 - '@luma.gl/core': ~9.3.3 - '@luma.gl/engine': ~9.3.3 - - '@deck.gl/mapbox@9.3.7': - resolution: {integrity: sha512-hamgwBS2BbB8DHOjYWwPMrFki+KhcedjoHv/9cUpQHnjfXUswzmyhAURuyowO/tAVJb3vF+CmMzaDVUTlI40Sw==} - peerDependencies: - '@deck.gl/core': ~9.3.0 - '@luma.gl/core': ~9.3.3 - '@math.gl/web-mercator': ^4.1.0 - '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} @@ -764,49 +734,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@loaders.gl/core@4.4.3': - resolution: {integrity: sha512-D6kXFdpUtYwoqS5OQLLaLELkHlS3qIdcSgzVvsh/MinRteeVIITJojqEc/lmDx1zVR3j6WND7yPGF4i4aOwiOg==} - - '@loaders.gl/images@4.4.3': - resolution: {integrity: sha512-a4C6x+4GZUchf+IwpdBOvyGeLGSbGOVob+WSWfGUezEQ4gqu1zS1pn3lCX3ZTL5P+Ch3v6KKwPGdO5YdTd52Ew==} - peerDependencies: - '@loaders.gl/core': ~4.4.0 - - '@loaders.gl/loader-utils@4.4.3': - resolution: {integrity: sha512-5yt1OqZPYR3d+xFAqtzSKO24Hd7019KqN+iOWp7XBKPQBS+sAEhAnmSTnO1axo45IEi14J3FhMDk+ndqBoSKEQ==} - - '@loaders.gl/schema-utils@4.4.3': - resolution: {integrity: sha512-TggzQWkzf9pIYbj8I9RlTk33kwXslvDkY1nnw/OL/hika6qTls1G127qK5m9skiAjElk5ZkvQLQcwhOboZXZeA==} - peerDependencies: - '@loaders.gl/core': ~4.4.0 - - '@loaders.gl/schema@4.4.3': - resolution: {integrity: sha512-tDb/rOn44nHWvMFSOaAk1/pQcQcusxirGCM1O5BMJR0PQ71UrCHey56rsbcf7/wGhvyRwPtX+oiMzlJ9TmN8vQ==} - - '@loaders.gl/worker-utils@4.4.3': - resolution: {integrity: sha512-RZt/NwFXm6Kx3Fn/rqiW3Alse9Z0XtBktH/EFAp8W6LvsKuxpRMjULqGfybTu2waRXRYUNYZ6zGs9aOWbtDRLw==} - peerDependencies: - '@loaders.gl/core': ~4.4.0 - - '@luma.gl/core@9.3.6': - resolution: {integrity: sha512-eqHnCPh2xHYkdd9rEkiIIkGMixNiJkq1ROrnTob6npvmZNVHXL0ubIw5KueL7rqW0+J1tm+p2+TXZaCmn0sP7Q==} - - '@luma.gl/engine@9.3.6': - resolution: {integrity: sha512-NYTdhn2NaH/MjN8qXCl2ukrT1Ac9iTKu1mgN0wz11XRd1QYnlMNBXswRROD7IZ2PUsBWdmYHc9qE8wKBQqMuIA==} - peerDependencies: - '@luma.gl/core': ~9.3.0 - '@luma.gl/shadertools': ~9.3.0 - - '@luma.gl/shadertools@9.3.6': - resolution: {integrity: sha512-dDuD8lCOkAE1L7hJGZEyZAi7upR1HG3wEEIQ1gCLaTTbJWC7tNtnVz853lqUA+VXgjgS9NiQFFRcosiIZmW4Vg==} - peerDependencies: - '@luma.gl/core': ~9.3.0 - - '@luma.gl/webgl@9.3.6': - resolution: {integrity: sha512-tGm7FGWPmJKxGZMvkRPRi219x3tKmBxR7Uke09nTp2ujNak/O5V9xPIQ9lUBGTxqAb8U2yjKkXG8j+f/4b2+sw==} - peerDependencies: - '@luma.gl/core': ~9.3.0 - '@mapbox/geojson-rewind@0.5.2': resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} hasBin: true @@ -835,21 +762,6 @@ packages: resolution: {integrity: sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==} hasBin: true - '@math.gl/core@4.1.0': - resolution: {integrity: sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA==} - - '@math.gl/polygon@4.1.0': - resolution: {integrity: sha512-YA/9PzaCRHbIP5/0E9uTYrqe+jsYTQoqoDWhf6/b0Ixz8bPZBaGDEafLg3z7ffBomZLacUty9U3TlPjqMtzPjA==} - - '@math.gl/sun@4.1.0': - resolution: {integrity: sha512-i3q6OCBLSZ5wgZVhXg+X7gsjY/TUtuFW/2KBiq/U1ypLso3S4sEykoU/MGjxUv1xiiGtr+v8TeMbO1OBIh/HmA==} - - '@math.gl/types@4.1.0': - resolution: {integrity: sha512-clYZdHcmRvMzVK5fjeDkQlHUzXQSNdZ7s4xOqC3nJPgz4C/TZkUecTo9YS4PruZqtDda/ag4erndP0MIn40dGA==} - - '@math.gl/web-mercator@4.1.0': - resolution: {integrity: sha512-HZo3vO5GCMkXJThxRJ5/QYUYRr3XumfT8CzNNCwoJfinxy5NtKUd7dusNTXn7yJ40UoB8FMIwkVwNlqaiRZZAw==} - '@mermaid-js/parser@1.2.0': resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} @@ -877,15 +789,6 @@ packages: engines: {node: '>=18'} hasBin: true - '@probe.gl/env@4.1.1': - resolution: {integrity: sha512-+68seNDMVsEegRB47pFA/Ws1Fjy8agcFYXxzorKToyPcD6zd+gZ5uhwoLd7TzsSw6Ydns//2KEszWn+EnNHTbA==} - - '@probe.gl/log@4.1.1': - resolution: {integrity: sha512-kcZs9BT44pL7hS1OkRGKYRXI/SN9KejUlPD+BY40DguRLzdC5tLG/28WGMyfKdn/51GT4a0p+0P8xvDn1Ez+Kg==} - - '@probe.gl/stats@4.1.1': - resolution: {integrity: sha512-4VpAyMHOqydSvPlEyHwXaE+AkIdR03nX+Qhlxsk2D/IW4OVmDZgIsvJB1cDzyEEtcfKcnaEbfXeiPgejBceT6g==} - '@radix-ui/number@1.1.2': resolution: {integrity: sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==} @@ -1714,12 +1617,6 @@ packages: '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/command-line-args@5.2.3': - resolution: {integrity: sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==} - - '@types/command-line-usage@5.0.4': - resolution: {integrity: sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==} - '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -1855,9 +1752,6 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} - '@types/offscreencanvas@2019.7.3': - resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/pbf@3.0.5': resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} @@ -2090,10 +1984,6 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - apache-arrow@21.1.0: - resolution: {integrity: sha512-kQrYLxhC+NTVVZ4CCzGF6L/uPVOzJmD1T3XgbiUnP7oTeVFOFgEUu6IKNwCDkpFoBVqDKQivlX4RUFqqnWFlEA==} - hasBin: true - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2108,10 +1998,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - array-back@6.2.3: - resolution: {integrity: sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==} - engines: {node: '>=12.17'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2156,10 +2042,6 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk-template@0.4.0: - resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} - engines: {node: '>=12'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2211,19 +2093,6 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - command-line-args@6.0.2: - resolution: {integrity: sha512-AIjYVxrV9X752LmPDLbVYv8aMCuHPSLZJXEo2qo/xJfv+NYhaZ4sMSF01rM+gHPaMgvPM0l5D/F+Qx+i2WfSmQ==} - engines: {node: '>=12.20'} - peerDependencies: - '@75lb/nature': latest - peerDependenciesMeta: - '@75lb/nature': - optional: true - - command-line-usage@7.0.4: - resolution: {integrity: sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==} - engines: {node: '>=12.20.0'} - commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -2481,9 +2350,6 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - earcut@2.2.4: - resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} - earcut@3.2.3: resolution: {integrity: sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==} @@ -2666,15 +2532,6 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - find-replace@5.0.2: - resolution: {integrity: sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==} - engines: {node: '>=14'} - peerDependencies: - '@75lb/nature': latest - peerDependenciesMeta: - '@75lb/nature': - optional: true - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -2683,9 +2540,6 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatbuffers@25.9.23: - resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} - flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} @@ -2974,10 +2828,6 @@ packages: engines: {node: '>=6'} hasBin: true - json-bignum@0.0.3: - resolution: {integrity: sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==} - engines: {node: '>=0.8'} - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3110,9 +2960,6 @@ packages: lodash-es@4.18.1: resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} - lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -3361,9 +3208,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - mjolnir.js@3.0.1: - resolution: {integrity: sha512-/RMi8Jm3NKleOkVI8D2ai+1OVwtfRJsSVBVjbTXNm83nfsN4uORYaN3u1/hsg5CqVI+di8enTkvgDNDOywn6cQ==} - motion-dom@12.42.2: resolution: {integrity: sha512-5gIMWLp/PycBtJRJWRgjxke5n8dlvkSn2DrYW+tr3XcqAZY1xZh6BJyooJXCM8wdfM7wfMjkBJNLge1CKPUIRA==} @@ -3805,10 +3649,6 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - table-layout@4.1.1: - resolution: {integrity: sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==} - engines: {node: '>=12.17'} - tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -3903,10 +3743,6 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - typical@7.3.0: - resolution: {integrity: sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==} - engines: {node: '>=12.17'} - undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} @@ -4120,10 +3956,6 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrapjs@5.1.1: - resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} - engines: {node: '>=12.17'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -4491,51 +4323,6 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@deck.gl/core@9.3.7': - dependencies: - '@loaders.gl/core': 4.4.3 - '@loaders.gl/images': 4.4.3(@loaders.gl/core@4.4.3) - '@luma.gl/core': 9.3.6 - '@luma.gl/engine': 9.3.6(@luma.gl/core@9.3.6)(@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6)) - '@luma.gl/shadertools': 9.3.6(@luma.gl/core@9.3.6) - '@luma.gl/webgl': 9.3.6(@luma.gl/core@9.3.6) - '@math.gl/core': 4.1.0 - '@math.gl/sun': 4.1.0 - '@math.gl/types': 4.1.0 - '@math.gl/web-mercator': 4.1.0 - '@probe.gl/env': 4.1.1 - '@probe.gl/log': 4.1.1 - '@probe.gl/stats': 4.1.1 - '@types/offscreencanvas': 2019.7.3 - gl-matrix: 3.4.4 - mjolnir.js: 3.0.1 - transitivePeerDependencies: - - '@75lb/nature' - - '@deck.gl/layers@9.3.7(@deck.gl/core@9.3.7)(@loaders.gl/core@4.4.3)(@luma.gl/core@9.3.6)(@luma.gl/engine@9.3.6(@luma.gl/core@9.3.6)(@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6)))': - dependencies: - '@deck.gl/core': 9.3.7 - '@loaders.gl/core': 4.4.3 - '@loaders.gl/images': 4.4.3(@loaders.gl/core@4.4.3) - '@loaders.gl/schema': 4.4.3 - '@luma.gl/core': 9.3.6 - '@luma.gl/engine': 9.3.6(@luma.gl/core@9.3.6)(@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6)) - '@luma.gl/shadertools': 9.3.6(@luma.gl/core@9.3.6) - '@mapbox/tiny-sdf': 2.2.0 - '@math.gl/core': 4.1.0 - '@math.gl/polygon': 4.1.0 - '@math.gl/web-mercator': 4.1.0 - '@types/geojson': 7946.0.16 - earcut: 2.2.4 - transitivePeerDependencies: - - '@75lb/nature' - - '@deck.gl/mapbox@9.3.7(@deck.gl/core@9.3.7)(@luma.gl/core@9.3.6)(@math.gl/web-mercator@4.1.0)': - dependencies: - '@deck.gl/core': 9.3.7 - '@luma.gl/core': 9.3.6 - '@math.gl/web-mercator': 4.1.0 - '@esbuild/aix-ppc64@0.28.1': optional: true @@ -4749,82 +4536,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@loaders.gl/core@4.4.3': - dependencies: - '@loaders.gl/loader-utils': 4.4.3(@loaders.gl/core@4.4.3) - '@loaders.gl/schema': 4.4.3 - '@loaders.gl/schema-utils': 4.4.3(@loaders.gl/core@4.4.3) - '@loaders.gl/worker-utils': 4.4.3(@loaders.gl/core@4.4.3) - '@probe.gl/log': 4.1.1 - transitivePeerDependencies: - - '@75lb/nature' - - '@loaders.gl/images@4.4.3(@loaders.gl/core@4.4.3)': - dependencies: - '@loaders.gl/core': 4.4.3 - '@loaders.gl/loader-utils': 4.4.3(@loaders.gl/core@4.4.3) - transitivePeerDependencies: - - '@75lb/nature' - - '@loaders.gl/loader-utils@4.4.3(@loaders.gl/core@4.4.3)': - dependencies: - '@loaders.gl/schema': 4.4.3 - '@loaders.gl/worker-utils': 4.4.3(@loaders.gl/core@4.4.3) - '@probe.gl/log': 4.1.1 - '@probe.gl/stats': 4.1.1 - transitivePeerDependencies: - - '@75lb/nature' - - '@loaders.gl/core' - - '@loaders.gl/schema-utils@4.4.3(@loaders.gl/core@4.4.3)': - dependencies: - '@loaders.gl/core': 4.4.3 - '@loaders.gl/schema': 4.4.3 - '@types/geojson': 7946.0.16 - apache-arrow: 21.1.0 - transitivePeerDependencies: - - '@75lb/nature' - - '@loaders.gl/schema@4.4.3': - dependencies: - '@types/geojson': 7946.0.16 - apache-arrow: 21.1.0 - transitivePeerDependencies: - - '@75lb/nature' - - '@loaders.gl/worker-utils@4.4.3(@loaders.gl/core@4.4.3)': - dependencies: - '@loaders.gl/core': 4.4.3 - - '@luma.gl/core@9.3.6': - dependencies: - '@math.gl/types': 4.1.0 - '@probe.gl/env': 4.1.1 - '@probe.gl/log': 4.1.1 - '@probe.gl/stats': 4.1.1 - '@types/offscreencanvas': 2019.7.3 - - '@luma.gl/engine@9.3.6(@luma.gl/core@9.3.6)(@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6))': - dependencies: - '@luma.gl/core': 9.3.6 - '@luma.gl/shadertools': 9.3.6(@luma.gl/core@9.3.6) - '@math.gl/core': 4.1.0 - '@math.gl/types': 4.1.0 - '@probe.gl/log': 4.1.1 - '@probe.gl/stats': 4.1.1 - - '@luma.gl/shadertools@9.3.6(@luma.gl/core@9.3.6)': - dependencies: - '@luma.gl/core': 9.3.6 - '@math.gl/core': 4.1.0 - '@math.gl/types': 4.1.0 - - '@luma.gl/webgl@9.3.6(@luma.gl/core@9.3.6)': - dependencies: - '@luma.gl/core': 9.3.6 - '@math.gl/types': 4.1.0 - '@probe.gl/env': 4.1.1 - '@mapbox/geojson-rewind@0.5.2': dependencies: get-stream: 6.0.1 @@ -4854,22 +4565,6 @@ snapshots: rw: 1.3.3 tinyqueue: 3.0.0 - '@math.gl/core@4.1.0': - dependencies: - '@math.gl/types': 4.1.0 - - '@math.gl/polygon@4.1.0': - dependencies: - '@math.gl/core': 4.1.0 - - '@math.gl/sun@4.1.0': {} - - '@math.gl/types@4.1.0': {} - - '@math.gl/web-mercator@4.1.0': - dependencies: - '@math.gl/core': 4.1.0 - '@mermaid-js/parser@1.2.0': dependencies: '@chevrotain/types': 11.1.2 @@ -4902,14 +4597,6 @@ snapshots: dependencies: playwright: 1.61.1 - '@probe.gl/env@4.1.1': {} - - '@probe.gl/log@4.1.1': - dependencies: - '@probe.gl/env': 4.1.1 - - '@probe.gl/stats@4.1.1': {} - '@radix-ui/number@1.1.2': {} '@radix-ui/primitive@1.1.6': {} @@ -5550,6 +5237,7 @@ snapshots: '@swc/helpers@0.5.23': dependencies: tslib: 2.8.1 + optional: true '@swc/types@0.1.27': dependencies: @@ -5664,10 +5352,6 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - '@types/command-line-args@5.2.3': {} - - '@types/command-line-usage@5.0.4': {} - '@types/d3-array@3.2.2': {} '@types/d3-axis@3.0.6': @@ -5829,8 +5513,6 @@ snapshots: dependencies: undici-types: 7.18.2 - '@types/offscreencanvas@2019.7.3': {} - '@types/pbf@3.0.5': {} '@types/react-dom@19.2.3(@types/react@19.2.17)': @@ -6009,20 +5691,6 @@ snapshots: ansi-styles@5.2.0: {} - apache-arrow@21.1.0: - dependencies: - '@swc/helpers': 0.5.23 - '@types/command-line-args': 5.2.3 - '@types/command-line-usage': 5.0.4 - '@types/node': 24.13.3 - command-line-args: 6.0.2 - command-line-usage: 7.0.4 - flatbuffers: 25.9.23 - json-bignum: 0.0.3 - tslib: 2.8.1 - transitivePeerDependencies: - - '@75lb/nature' - argparse@2.0.1: {} aria-hidden@1.2.6: @@ -6035,8 +5703,6 @@ snapshots: aria-query@5.3.2: {} - array-back@6.2.3: {} - assertion-error@2.0.1: {} asynckit@0.4.0: {} @@ -6073,10 +5739,6 @@ snapshots: chai@6.2.2: {} - chalk-template@0.4.0: - dependencies: - chalk: 4.1.2 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -6128,20 +5790,6 @@ snapshots: comma-separated-tokens@2.0.3: {} - command-line-args@6.0.2: - dependencies: - array-back: 6.2.3 - find-replace: 5.0.2 - lodash.camelcase: 4.3.0 - typical: 7.3.0 - - command-line-usage@7.0.4: - dependencies: - array-back: 6.2.3 - chalk-template: 0.4.0 - table-layout: 4.1.1 - typical: 7.3.0 - commander@14.0.3: {} commander@7.2.0: {} @@ -6410,8 +6058,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - earcut@2.2.4: {} - earcut@3.2.3: {} echarts-for-react@3.0.6(echarts@6.1.0)(react@19.2.7): @@ -6623,8 +6269,6 @@ snapshots: dependencies: flat-cache: 4.0.1 - find-replace@5.0.2: {} - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -6635,8 +6279,6 @@ snapshots: flatted: 3.4.2 keyv: 4.5.4 - flatbuffers@25.9.23: {} - flatted@3.4.2: {} form-data@4.0.6: @@ -6981,8 +6623,6 @@ snapshots: jsesc@3.1.0: {} - json-bignum@0.0.3: {} - json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -7077,8 +6717,6 @@ snapshots: lodash-es@4.18.1: {} - lodash.camelcase@4.3.0: {} - lodash.merge@4.6.2: {} longest-streak@3.1.0: {} @@ -7594,8 +7232,6 @@ snapshots: minimist@1.2.8: {} - mjolnir.js@3.0.1: {} - motion-dom@12.42.2: dependencies: motion-utils: 12.39.0 @@ -8099,11 +7735,6 @@ snapshots: symbol-tree@3.2.4: {} - table-layout@4.1.1: - dependencies: - array-back: 6.2.3 - wordwrapjs: 5.1.1 - tagged-tag@1.0.0: {} tailwind-merge@3.6.0: {} @@ -8194,8 +7825,6 @@ snapshots: '@typescript/typescript-win32-arm64': 7.0.2 '@typescript/typescript-win32-x64': 7.0.2 - typical@7.3.0: {} - undici-types@7.18.2: {} unified@11.0.5: @@ -8377,8 +8006,6 @@ snapshots: word-wrap@1.2.5: {} - wordwrapjs@5.1.1: {} - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 diff --git a/src/app/app.e2e.ts b/src/app/app.e2e.ts index f8aba22..54d13b2 100644 --- a/src/app/app.e2e.ts +++ b/src/app/app.e2e.ts @@ -80,7 +80,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 }) => { @@ -100,7 +100,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("/"); @@ -116,6 +116,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/features/agent/components/agent-collapsed-rail.tsx b/src/features/agent/components/agent-collapsed-rail.tsx index db3569c..f3d3a99 100644 --- a/src/features/agent/components/agent-collapsed-rail.tsx +++ b/src/features/agent/components/agent-collapsed-rail.tsx @@ -28,7 +28,7 @@ export function AgentCollapsedRail({ aria-label={expandLabel} title={expandLabel} onClick={onExpand} - className="agent-rail-item surface-control group relative flex h-14 w-full items-center justify-center rounded-xl border transition-[background-color,transform] hover:bg-white active:scale-95" + className="agent-rail-item surface-control group relative flex h-14 w-full items-center justify-center rounded-xl border hover:bg-white" > diff --git a/src/features/agent/components/agent-command-panel.tsx b/src/features/agent/components/agent-command-panel.tsx index f6e29fa..6ccd1bc 100644 --- a/src/features/agent/components/agent-command-panel.tsx +++ b/src/features/agent/components/agent-command-panel.tsx @@ -19,7 +19,7 @@ import { X } from "lucide-react"; import { AnimatePresence, MotionConfig, motion, useReducedMotion } from "motion/react"; -import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; +import { useCallback, useEffect, useId, useMemo, useRef, useState, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { useStickToBottomContext } from "use-stick-to-bottom"; import { showMapNotice } from "@/features/map/core"; @@ -48,6 +48,7 @@ import { } from "@/shared/ui/dropdown-menu"; import { Button } from "@/shared/ui/button"; import { cn } from "@/shared/ui/cn"; +import { StatusBadge, StatusDot, type StatusTone } from "@/shared/ui/status"; import type { AgentChatSessionSummary } from "../api/client"; import { AgentPersona } from "./agent-persona"; import { @@ -70,6 +71,7 @@ import { import type { AgentApprovalMode, AgentChatMessage, + AgentConnectionStatus, AgentModelOption, AgentPermissionReply, AgentPermissionRequest, @@ -78,10 +80,7 @@ import type { AgentUiResult } from "../types"; -export type AgentCommandPanelPresentation = - | "desktop-dock" - | "desktop-floating" - | "mobile-sheet"; +export type AgentCommandPanelPresentation = "desktop-dock" | "desktop-floating" | "mobile-sheet"; type AgentCommandPanelProps = { presentation?: AgentCommandPanelPresentation; @@ -92,6 +91,7 @@ type AgentCommandPanelProps = { sessionHistoryLoading?: boolean; activeSessionId?: string | null; statusLabel?: string; + connectionStatus?: AgentConnectionStatus; streaming?: boolean; messages?: AgentChatMessage[]; streamRenderState?: AgentStreamRenderState; @@ -142,6 +142,7 @@ export function AgentCommandPanel({ sessionHistoryLoading = false, activeSessionId, statusLabel = "Agent 后端连接中", + connectionStatus = "connecting", streaming = false, messages = [], streamRenderState = {}, @@ -167,6 +168,12 @@ export function AgentCommandPanel({ const [historyOpen, setHistoryOpen] = useState(false); const [loadingSessionId, setLoadingSessionId] = useState(null); const [scrollRequestId, setScrollRequestId] = useState(0); + const historyPanelId = useId(); + const historyTriggerRef = useRef(null); + const historyPanelRef = useRef(null); + const desktopFloating = presentation === "desktop-floating"; + const floatingPresentation = desktopFloating || presentation === "mobile-sheet"; + const hasConversation = messages.length > 0 || streaming; const trimmedPrompt = prompt.trim(); const { speechState, @@ -202,6 +209,46 @@ export function AgentCommandPanel({ } }, [historyOpen, onRefreshHistory]); + useEffect(() => { + if (!historyOpen) { + return; + } + + const closeHistoryOnOutsidePointer = (event: PointerEvent) => { + const target = event.target; + if (!(target instanceof Node)) { + return; + } + + if ( + historyPanelRef.current?.contains(target) || + historyTriggerRef.current?.contains(target) + ) { + return; + } + + setHistoryOpen(false); + }; + const closeHistoryOnEscape = (event: KeyboardEvent) => { + if (event.key !== "Escape") { + return; + } + + event.preventDefault(); + event.stopPropagation(); + setHistoryOpen(false); + window.requestAnimationFrame(() => historyTriggerRef.current?.focus()); + }; + + document.addEventListener("pointerdown", closeHistoryOnOutsidePointer, true); + document.addEventListener("keydown", closeHistoryOnEscape); + + return () => { + document.removeEventListener("pointerdown", closeHistoryOnOutsidePointer, true); + document.removeEventListener("keydown", closeHistoryOnEscape); + }; + }, [historyOpen]); + useEffect(() => { stopSpeech(); }, [activeSessionId, stopSpeech]); @@ -221,155 +268,217 @@ export function AgentCommandPanel({ setPrompt(nextPrompt); }); }; + const historyPanel = ( + { + setLoadingSessionId(nextSessionId); + void Promise.resolve(onLoadHistorySession?.(nextSessionId)) + .then(() => setHistoryOpen(false)) + .finally(() => setLoadingSessionId(null)); + }} + onRenameSession={onRenameHistorySession} + onDeleteSession={onDeleteHistorySession} + /> + ); + const operationalBrief = ( + + ); return ( ); } -function PanelSection({ title, description, children }: { title: string; description: string; children: React.ReactNode }) { - return

{title}

{description}

{children}
; +function PanelSection({ + title, + description, + children +}: { + title: string; + description: string; + children: React.ReactNode; +}) { + return ( +
+
+

{title}

+

{description}

+
+ {children} +
+ ); } function Field({ label, children }: { label: string; children: React.ReactNode }) { - return ; + return ( + + ); } -function ColorField({ label, value, onChange }: { label: string; value: string; onChange: (value: string) => void }) { - return
onChange(event.target.value.toUpperCase())} className="h-5 w-7 cursor-pointer border-0 bg-transparent p-0" />{value}
; +function ToggleField({ + label, + checked, + onChange +}: { + label: string; + checked: boolean; + onChange: (checked: boolean) => void; +}) { + return ( + + ); } -function RangeField({ label, min, max, step, value, onChange }: { label: string; min: number; max: number; step: number; value: number; onChange: (value: number) => void }) { - return onChange(Number(event.target.value))} className="h-6 w-full accent-blue-600" />; +function ColorField({ + label, + value, + onChange +}: { + label: string; + value: string; + onChange: (value: string) => void; +}) { + return ( + +
+ onChange(event.target.value.toUpperCase())} + className="h-5 w-7 cursor-pointer border-0 bg-transparent p-0" + /> + {value} +
+
+ ); } -const inputClassName = "h-9 w-full rounded-lg border border-slate-200 bg-white/80 px-2.5 text-xs text-slate-800 outline-hidden transition focus:border-blue-400 focus:ring-2 focus:ring-blue-500/15"; -const primaryButtonClassName = "inline-flex h-9 items-center justify-center gap-1.5 rounded-lg bg-blue-600 px-3 text-xs font-semibold text-white transition hover:bg-blue-700 active:scale-95 disabled:cursor-not-allowed disabled:scale-100 disabled:opacity-45"; -const secondaryButtonClassName = "inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-slate-200 bg-white/70 px-3 text-xs font-semibold text-slate-700 transition hover:bg-white active:scale-95 disabled:cursor-not-allowed disabled:scale-100 disabled:opacity-45"; +function RangeField({ + label, + min, + max, + step, + value, + onChange +}: { + label: string; + min: number; + max: number; + step: number; + value: number; + onChange: (value: number) => void; +}) { + return ( + + onChange(Number(event.target.value))} + className="h-6 w-full accent-blue-600" + /> + + ); +} + +function StatusText({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + +const inputClassName = + "h-9 w-full rounded-lg border border-slate-200 bg-white/80 px-2.5 text-xs text-slate-800 outline-hidden transition focus:border-blue-400 focus:ring-2 focus:ring-blue-500/15"; diff --git a/src/features/workbench/components/mobile-workbench-sheet.tsx b/src/features/workbench/components/mobile-workbench-sheet.tsx index 2ecb775..c8e07c9 100644 --- a/src/features/workbench/components/mobile-workbench-sheet.tsx +++ b/src/features/workbench/components/mobile-workbench-sheet.tsx @@ -149,7 +149,7 @@ export function MobileWorkbenchSheet({ )} style={{ height: dragHeight ?? restingHeight }} > -
+
) : null} @@ -349,19 +357,19 @@ export function ScheduledConditionFeed({ mobileSheet ? "flex flex-1" : expanded - ? "scheduled-feed-layout-expanded" + ? "scheduled-feed-layout-expanded flex-1" : "scheduled-feed-layout-collapsed" )} >
-
+
); } @@ -469,7 +490,7 @@ function MenuAction({ "grid h-7 w-7 shrink-0 place-items-center border", MAP_ICON_CELL_RADIUS_CLASS_NAME, tone === "primary" && "border-blue-100 bg-blue-50 text-blue-700", - tone === "warning" && "border-orange-100 bg-orange-50 text-orange-700", + tone === "warning" && "status-icon status-tone-warning", tone === "default" && "border-slate-100 bg-slate-50 text-slate-600" )} > diff --git a/src/features/workbench/components/workbench-top-bar-styles.ts b/src/features/workbench/components/workbench-top-bar-styles.ts index 137274c..b130715 100644 --- a/src/features/workbench/components/workbench-top-bar-styles.ts +++ b/src/features/workbench/components/workbench-top-bar-styles.ts @@ -1,7 +1,16 @@ +import { buttonInteractionVariants } from "@/shared/ui/button-interaction"; +import { cn } from "@/shared/ui/cn"; + export const headerControlButtonClassName = - "inline-flex h-8 items-center gap-2 whitespace-nowrap rounded-full border border-transparent bg-transparent text-sm font-semibold text-slate-700 transition-colors hover:bg-white/70 hover:text-blue-700 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-600/20 focus-visible:ring-offset-2 data-[state=open]:bg-white/90 data-[state=open]:text-blue-700"; + cn( + buttonInteractionVariants({ tone: "neutral" }), + "inline-flex h-8 items-center gap-2 whitespace-nowrap rounded-full border border-transparent bg-transparent text-sm font-semibold after:absolute after:-inset-1 after:content-['']" + ); + +export const compactHeaderControlButtonClassName = + "h-10 w-10 justify-center px-0"; export const headerControlIconClassName = - "grid h-5 w-5 shrink-0 place-items-center rounded-full bg-slate-100/80 text-slate-500 transition-colors group-hover:bg-blue-50 group-hover:text-blue-700 group-data-[state=open]:bg-blue-50 group-data-[state=open]:text-blue-700"; + "header-control-icon grid h-5 w-5 shrink-0 place-items-center rounded-full bg-slate-100/80 text-slate-500 transition-colors group-hover:bg-blue-50 group-hover:text-blue-700 group-data-[state=open]:bg-blue-50 group-data-[state=open]:text-blue-700"; export const compactHeaderTextClassName = "hidden 2xl:inline"; diff --git a/src/features/workbench/components/workbench-top-bar.tsx b/src/features/workbench/components/workbench-top-bar.tsx index 01edba1..595bb5c 100644 --- a/src/features/workbench/components/workbench-top-bar.tsx +++ b/src/features/workbench/components/workbench-top-bar.tsx @@ -138,26 +138,18 @@ export function WorkbenchTopBar({ ) : null}
-
+
{devPanelEnabled ? (
@@ -996,7 +998,7 @@ export function MapWorkbenchPage() { aria-label="打开工况任务" title="打开工况任务" onClick={toggleConditionFeedForViewport} - className="acrylic-control grid h-11 w-11 shrink-0 place-items-center rounded-xl border text-blue-700 active:scale-95" + className="acrylic-control grid h-11 w-11 shrink-0 place-items-center rounded-xl border text-blue-700" >