Skip to content

♻️ 新 UI 重写:shadcn/ui + Tailwind v4 + React 19 全面重构表现层#1514

Draft
CodFrm wants to merge 180 commits into
release/v1.4-agentfrom
develop/new-ui
Draft

♻️ 新 UI 重写:shadcn/ui + Tailwind v4 + React 19 全面重构表现层#1514
CodFrm wants to merge 180 commits into
release/v1.4-agentfrom
develop/new-ui

Conversation

@CodFrm

@CodFrm CodFrm commented Jun 17, 2026

Copy link
Copy Markdown
Member

Checklist / 检查清单

  • Fixes mentioned issues / 修复已提及的问题
  • Code reviewed by human / 代码通过人工检查
  • Changes tested / 已完成测试(单元测试已覆盖,真机可视化验收进行中)

设计稿.pen.zip

Description / 描述

🚧 草稿 PR:整个新 UI 重写的集成 PR,合并目标为 main。目前仍在做各页面的真机可视化验收,完成后再转为正式 PR。

使用 shadcn/ui + Tailwind CSS v4 + React 19src/pages/ 表现层进行从零重写,替换原有的 Arco Design + UnoCSS 技术栈。设计系统(颜色令牌、组件、布局/动效/状态规范)统一沉淀在 docs/DESIGN.md,所有页面同时适配亮色/暗色主题(Tailwind dark: 变体 + src/index.css 设计令牌)。

已完成页面

核心管理页

  • 脚本列表(ScriptList,含表格/卡片、过滤侧栏、批量操作、移动端)
  • 订阅列表(SubscribeList)
  • 脚本编辑器(ScriptEditor,Monaco + 多标签 + 代码/资源/设置/存储面板)
  • 日志(Logger)、设置(Setting)、工具(Tools)
  • 弹出层(popup)

独立页面

  • 安装页(install,身份→权限→代码 信任优先布局,脚本/订阅/Skill 安装、本地文件监听、移动端)
  • 数据导入页(import,数据导入/备份恢复)
  • 授权确认页(confirm,时长选择 + 允许/拒绝)
  • 批量更新页(batchupdate,表格勾选 + 风险标签 + 已忽略分组)

Agent 套件(7 页)

  • 会话(AgentChat,三栏可折叠 + 流式 + thinking/工具调用/任务列表/ask_user/附件富块 + 移动导航抽屉)
  • 模型服务(AgentProvider)、Skills、MCP、定时任务(AgentTasks)、OPFS 文件浏览器、设置(AgentSettings)

其它

  • i18n:7 种语言(zh-CN / zh-TW / en-US / ja-JP / de-DE / ru-RU / vi-VN)同步更新
  • 测试:遵循 TDD,使用 vitest + Testing Library,新页面均有单元/组件测试覆盖
  • 文档:新增 docs/DESIGN.md,更新 docs/DEVELOP.md / docs/README.md 等贡献者文档

待办(转正式 PR 前)

  • 各页面真机可视化验收(亮色/暗色 + 桌面/移动)
  • 页内功能与旧版逐项对账复核

Screenshots / 截图

CodFrm added 30 commits April 6, 2026 00:14
移除基于 Arco Design + UnoCSS 的旧 UI 层与相关依赖,为下一版
基于 Tailwind CSS + shadcn/ui 的 UI 重构做准备。

- 删除 6 个页面(options/popup/install/confirm/import/batchupdate)、所有 UI 组件、HTML 模板和 CSS
- 卸载 16 个 UI 相关依赖(@arco-design/web-react、unocss、@dnd-kit/*、react-dropzone、react-joyride、react-router-dom、react-icons、react-i18next、@playwright/test 等)
- 删除 e2e 测试目录与 Playwright 配置
- 更新 rspack.config.ts 移除 UI entry 和 HtmlRspackPlugin
- 更新技术栈文档(CLAUDE.md、copilot-instructions、CONTRIBUTING)

保留:非 UI 入口(service_worker/content/inject/offscreen/sandbox)、
monaco-editor、i18next、pages/store/{global,favicons,features/script}.ts
- 使用 Tailwind CSS + shadcn/ui 重构 popup 页面
- 实现完整业务逻辑:脚本列表、启用/禁用、删除、排除、GM 菜单等
- 添加 usePopupData hook 对接 service worker 后端 API 和实时订阅
- 新增 Popconfirm 组件用于删除确认
- 配置设计系统色彩令牌(品牌蓝、状态色、暗色模式)
- 搭建 options 页面入口(骨架)
- 新增 Sidebar 组件:导航、帮助中心菜单(hover触发)、主题切换、折叠
- 使用 HashRouter 配置路由(脚本列表/订阅/日志/工具/设置/编辑器)
- 提取 GithubIcon 组件替代 popup 和 sidebar 中的 inline SVG
- i18n 使用已有翻译 key,与 release/v1.4 保持一致
- 将 translation.json 拆分为 11 个命名空间(common/agent/script/editor/settings/install/popup/logs/guide/tools/permission)
- 升级 React 18→19、i18next 23→26,引入 react-i18next
- 还原 SW 层 popup 逻辑至 v1.5(不在 SW 中处理 i18n)
- 删除 Crowdin 配置、伪语言 ach-UG 及相关文档引用
- 修复 React 19 类型兼容(useRef、cloneElement)
# Conflicts:
#	package.json
#	pnpm-lock.yaml
#	src/app/service/service_worker/gm_api/gm_api.ts
#	src/app/service/service_worker/index.ts
#	src/locales/ach-UG/translation.json
#	src/locales/de-DE/translation.json
#	src/locales/en-US/translation.json
#	src/locales/ja-JP/translation.json
#	src/locales/ru-RU/translation.json
#	src/locales/vi-VN/translation.json
#	src/locales/zh-CN/translation.json
#	src/locales/zh-TW/translation.json
#	src/pages/components/CodeEditor/index.tsx
#	src/pages/components/UserConfigPanel/index.tsx
#	src/pages/components/layout/MainLayout.tsx
#	src/pages/install/App.tsx
#	src/pages/options/index.css
#	src/pages/options/routes/Logger.tsx
#	src/pages/options/routes/Setting.tsx
#	src/pages/options/routes/script/ScriptEditor.tsx
#	src/pages/popup/App.tsx
# Conflicts:
#	CONTRIBUTING.md
#	README.md
#	docs/CONTRIBUTING_EN.md
#	docs/CONTRIBUTING_RU.md
#	docs/README_RU.md
#	docs/README_ja.md
#	docs/README_zh-CN.md
#	docs/README_zh-TW.md
#	e2e/install.spec.ts
#	e2e/popup.spec.ts
#	e2e/script-editor.spec.ts
#	e2e/script-management.spec.ts
#	e2e/settings.spec.ts
#	e2e/vscode-connect.spec.ts
#	package.json
#	playwright.config.ts
#	pnpm-lock.yaml
#	src/app/service/content/scripting.ts
#	src/app/service/service_worker/gm_api/gm_api.ts
#	src/app/service/service_worker/index.ts
#	src/index.css
#	src/locales/README.md
#	src/locales/de-DE/translation.json
#	src/locales/en-US/translation.json
#	src/locales/ja-JP/translation.json
#	src/locales/locales.ts
#	src/locales/ru-RU/translation.json
#	src/locales/vi-VN/translation.json
#	src/locales/zh-CN/translation.json
#	src/locales/zh-TW/translation.json
#	src/manifest.json
#	src/pages/components/CodeEditor/index.tsx
#	src/pages/components/ScriptMenuList/index.tsx
#	src/pages/components/layout/MainLayout.tsx
#	src/pages/components/layout/Sider.tsx
#	src/pages/components/layout/SiderGuide.tsx
#	src/pages/confirm/App.tsx
#	src/pages/install/App.tsx
#	src/pages/install/hooks.tsx
#	src/pages/install/utils.ts
#	src/pages/options.html
#	src/pages/options/routes/AgentChat/ChatArea.tsx
#	src/pages/options/routes/AgentMcp.tsx
#	src/pages/options/routes/AgentOPFS.tsx
#	src/pages/options/routes/AgentProvider.tsx
#	src/pages/options/routes/AgentSettings.tsx
#	src/pages/options/routes/AgentSkills.tsx
#	src/pages/options/routes/AgentTasks.tsx
#	src/pages/options/routes/ScriptList/components.tsx
#	src/pages/options/routes/ScriptList/index.tsx
#	src/pages/options/routes/Setting.tsx
#	src/pages/options/routes/SubscribeList.tsx
#	src/pages/options/routes/Tools.tsx
#	src/pages/options/routes/script/ScriptEditor.tsx
#	src/pages/options/routes/script/index.css
#	src/pages/popup.html
#	src/pages/popup/App.tsx
#	src/pages/template.html
#	tests/pages/options/MainLayout.test.tsx
cyfung1031 and others added 8 commits June 21, 2026 15:13
新增 no-i18n-default-value / no-raw-color-classname 自定义规则及 harness 测试;eslint.config 升级 ecmaVersion、react-hooks recommended-latest,将 exhaustive-deps / jsx-no-literals / no-i18n-default-value 提级为 error,禁止 @radix-ui/react-* 单包导入。按约定全量整改:补 data-slot、改用设计令牌、合并 radix-ui 导入,并同步 AGENTS/DEVELOP/copilot 文档。
@cyfung1031

This comment was marked as outdated.

- 恢复 data-panel.test.tsx(组件仍被 5 处引用)与 toast.test.ts 的 dismiss/promise 透传用例,断言均已对照当前实现确认
- AGENTS.md 修正 no-restricted-syntax forwardRef 作用域(实为 src/pages/**,非 ui/**),并补充 projectService 类型感知规则(no-floating-promises 等)说明
@CodFrm

This comment was marked as outdated.

@cyfung1031

cyfung1031 commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

项目已经使用 React 19。当前重点是降低 Options UI 的 initial loading、控制大量 Script 与 Monaco Editor 的资源占用,并修复 Search race condition。

优先级 项目 最终确认 建议
Route-level code splitting 仍存在。options/App.tsx 仍同步 import 所有主要 routes。 使用 React.lazy + Suspense 延迟加载 ScriptEditor、Agent、Settings、Tools 等 routes。
Search race condition 已通过测试确认。旧请求晚返回时会污染当前 Search cache。 SearchFilter 内使用 request ID、keyword check 或 AbortController,禁止旧响应写入 cache。
Script list virtualization 仍存在。Table、desktop cards、mobile cards 都会渲染完整列表。 使用 @tanstack/react-virtualreact-window;先对超过一定数量的非 drag 状态启用。
Monaco Editor memory policy 仍存在。所有已打开 tabs 都常驻挂载,没有数量上限。 先进行 memory profiling,再增加 LRU live-editor limit、view state 保存和旧 Editor disposal。
Derived filtering state 仍存在。同步 filtering 仍在 useEffect 中计算并写入 state。 使用 useMemo 计算同步 filters,只把 async keyword matches 保存在 state。
React 19 async primitives 尚未采用。Batch operations、search、save 等仍手动管理 async state。 在确认存在 UI blocking 后,逐步使用 useTransitionuseOptimisticuseActionState
Editor route preload 尚未实现。编辑链接没有 hover/focus preload。 完成 route lazy loading 后,使用 dynamic import() 预加载 Editor chunk。
React Compiler 尚未启用 production transform,但准备工作已部分完成。 保留 compiler-aware ESLint,先在纯 UI leaf components 上试用并进行 benchmark。

已解决或无需处理

项目 最终确认
React 19 ref prop 已完成。CodeEditor 已使用普通 ref prop,ESLint 也禁止新增 forwardRef
Compiler-aware lint 已完成。当前 eslint-plugin-react-hooksrecommended-latest rules 已启用。
Sort mutation purity 已解决。reindexScriptList 会建立新对象,不再直接修改原 Script。
CodePane cursor listener leak 未确认存在。虽然没有单独保存 listener disposable,但 Monaco Editor disposal 会清理其 event emitter;目前没有证据表明发生 leak。
Search effect cleanup 部分完成。现有 alive guard 能阻止旧 effect 更新 React state,但不能阻止旧响应污染共享 cache。

推荐实施顺序

  1. 修复已确认的 Search race condition。
  2. 为 Options routes 增加 React.lazy + Suspense
  3. 增加 Editor route preload。
  4. 对大量 Script 进行 performance benchmark,并实现 virtualization。
  5. 对 Monaco Editor 进行 memory profiling,再设计 LRU memory policy。
  6. 重构 filtering state。
  7. 最后评估 React 19 async primitives 和 React Compiler。

CodFrm and others added 13 commits June 21, 2026 17:23
Module-level `events` was shared across all SystemConfig instances,
causing test-isolation failures: leftover subscriptions from prior
tests inflated listenerCount, suppressing the `watch` call and leaving
`resolveRead` unassigned in the delayed-read test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EditorTabs, EditorToolbar, ScriptListPanel, MobileEditor all lacked
React.memo, causing them to re-render on every parent state change
(e.g. cursor-position status updates, markChanged on keypress).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useMemo for activeTab (replaces bare .find on every render)
- useCallback for handleSaveActive/As/Run — read active state from
  stateRef so deps stay minimal (just the doSave/As/Run functions)
- Stable dispatch wrappers: onActivateTab, onCloseOthers/Left/RightTab,
  onNewTab, onOpenScript (dispatch from useReducer is always stable)
- onBack stabilised with useCallback([navigate])
- All inline lambda props replaced with the stable versions above,
  so the four React.memo child components can now actually skip renders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
editorArea was recreated as inline JSX on every ScriptEditor render,
making MobileEditor.children always a new reference and defeating the
React.memo added to MobileEditor. Wrap it in useMemo with deps
[state.tabs, state.activeUuid, subView, activeTab, doSave, doSaveAs,
doRun] so the children reference is stable across unrelated renders
(e.g. cursor-position status updates).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants