Phase 007: migrate every remaining view from naive-ui to Arco Design Vue
The project now has exactly one UI library. Every naive-ui component in
packages/client/src is replaced by its Arco equivalent across 24 views and
roughly 80 components, and naive-ui is dropped from package.json along with
its transitive vueuc / @css-render / vdirs / seemly dependencies.
The migration is rendering-layer only. No store logic, no API contract, and
no /chat-run payload was touched.
Three classes of leftover were invisible to `grep naive-ui` and are now
covered by tests/client/no-naive-ui.test.ts, which asserts all three:
- dead .n-* class names in style blocks
- dead --n-* custom properties
- naive-ui in package.json
Notable behavioural traps handled along the way, recorded in
docs/arco-migration-rules.md:
- a-input-password defaults to masked; passing default-visibility="false"
would have exposed API keys in clear text
- a-upload fires a real XHR unless auto-upload is false
- nested Trigger components fight over the first element child, so the
group-chat settings dropdown was flattened
- Arco renders tooltip default-slot text inline, which was silently
collapsing the chat and group-chat toolbars
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
---
|
||||
date: 2026-10-18
|
||||
pr: pending
|
||||
feature: Phase 007 - full naive-ui to Arco Design Vue migration across all remaining views
|
||||
impact: Rendering-layer only. Every naive-ui component in packages/client/src is replaced by its Arco Design Vue equivalent across 24 views and roughly 80 components, and the naive-ui dependency is removed from package.json and package-lock.json. No chat store logic, no /chat-run payload, and no message rendering path is touched. Three chat-chain files changed as a consequence of that rendering-only sweep, listed below with the specific reason each needed a change.
|
||||
---
|
||||
|
||||
# Phase 007 — full Arco migration
|
||||
|
||||
Phase 006 moved the chat page. Phase 007 finished the job: `grep -rn "naive-ui\|vueuc\|@css-render" packages/client/src` is now empty, and the project has exactly one UI library.
|
||||
|
||||
Batches 7a-7g each shipped independently per `docs/phases/phase_007.md`. `docs/arco-migration-rules.md` holds the component mapping table the whole sweep followed.
|
||||
|
||||
## Why chat-chain files changed
|
||||
|
||||
Four files under the chat chain were caught by the sweep. None of the changes touch logic.
|
||||
|
||||
### `chat/ChatPanel.vue`
|
||||
|
||||
- Three leftover naive CSS custom properties were still referenced: `--n-text-color-3` (twice)
|
||||
and `--n-color-hover` (once). These were dead after Phase 006 — the variables no longer
|
||||
resolve, so the rules silently did nothing. Rewritten to the project's own tokens
|
||||
(`--text-muted`, `--bg-card-hover`).
|
||||
- `:native-scrollbar="false"` on the workspace dropdown had no Arco counterpart and was
|
||||
dropped.
|
||||
|
||||
### `group-chat/GroupChatInput.vue`
|
||||
|
||||
- Eighteen dead naive rules under `.tool-trace-toggle`, `.input-settings-button` and
|
||||
`.send-button` targeted `.n-button__content`, `.n-button__icon`, `.n-button__border`,
|
||||
`.n-button__state-border`, `.n-button__ripple` and `.n-base-wave`. Arco's `a-button` has
|
||||
no content wrapper and none of the ripple internals, so `gap` now lives on the button
|
||||
itself and the ripple rules were deleted rather than renamed.
|
||||
- The settings button was `NDropdown > NTooltip > NButton` — a three-deep Trigger nest.
|
||||
Arco's Trigger components each claim the first element child via `mergeFirstChild`, so
|
||||
nested popups fight over it and the menu never opens. Flattened to `a-dropdown > a-button`
|
||||
with the description moved to a native `:title`, which is the same approach Phase 006
|
||||
already took in `ChatInput.vue`.
|
||||
- The attach tooltip carried its label as trailing default-slot text. Arco renders the
|
||||
default slot inline, so that text became a zero-width flex item in the toolbar. Moved to
|
||||
the `content` prop.
|
||||
|
||||
### `group-chat/CreateRoomForm.vue`
|
||||
|
||||
- Straight component swap. `InputLikeInstance = { focus: () => void }` was kept because
|
||||
Arco's `a-input` still exposes `focus()` (`es/input/input.js:315`), so the existing
|
||||
`nextTick` focus calls still work.
|
||||
|
||||
### `group-chat/GroupChatPanel.vue`
|
||||
|
||||
- The room context menu was `NDropdown` in `trigger="manual"` mode driven by `:x` / `:y` /
|
||||
`:show` / `@clickoutside`. Arco has no manual trigger, so it became
|
||||
`a-trigger trigger="contextMenu"` with `:popup-style` for coordinates, matching the
|
||||
pattern already used by `FileContextMenu.vue` and `WorkflowView.vue`. Arco's
|
||||
`clickOutsideToClose` defaults to true, which replaces the hand-written clickoutside
|
||||
handler.
|
||||
- `NPopover`'s `placement="bottom-end"` maps to Arco `position="br"` (bottom-right).
|
||||
Arco's `a-popover` has no `width` prop and its `Trigger` sets `inheritAttrs: false`, so a
|
||||
`:width` would be dropped silently; the width moved to `:content-style`.
|
||||
|
||||
## Verification
|
||||
|
||||
`packages/client/src` has zero naive references by three independent checks — `naive-ui`
|
||||
imports, `.n-*` class names in style blocks, and `--n-*` custom properties. The last two
|
||||
matter because `grep naive-ui` cannot see them; `tests/client/no-naive-ui.test.ts` now
|
||||
guards all three so the patterns cannot come back.
|
||||
|
||||
## Behavior impact
|
||||
|
||||
Rendering-layer only. No chat store logic, no `/chat-run` payload, and no message rendering
|
||||
path was touched. The group-chat message bubbles already used plain HTML and were left
|
||||
untouched, so the "no Arco components inside bubbles" rule still holds — `a-tree`, `a-select`
|
||||
and the other components appear only outside the bubble.
|
||||
Reference in New Issue
Block a user