Skip to content

Latest commit

 

History

History
108 lines (81 loc) · 17.1 KB

File metadata and controls

108 lines (81 loc) · 17.1 KB
name UiDesign
description Governs renderer UI and UX design tokens, layout hierarchy, component patterns, copy, accessibility, and motion.
keywords
frontend
ui
design
tailwind
nuxt-ui
accessibility

UiDesign

范围

  • 覆盖:src/renderer/src/** 下的页面、组件、全局样式和 UI 文案;src/renderer/index.htmlsrc/renderer/src/assets/main.css;以及 renderer 侧 @nuxt/ui / Tailwind CSS 视觉约定。
  • 不覆盖:renderer 路由、store、bootstrap 和 API wrapper 所有权;见 guidelines/RendererProcess.md
  • 不覆盖:测试位置、Vitest project 或质量命令;见 guidelines/Testing.mdguidelines/QualityGates.md

规则

设计原则

  • MUST 让颜色表达状态,而不是装饰。颜色深浅用于表达 default、hover、active、selected、disabled、danger 等状态意图;新增颜色必须能说明它表达的状态或层级。证据:electron.vite.config.tssrc/renderer/src/components/layout/ActivityBar.vuesrc/renderer/src/pages/settings.vue
  • MUST 优先使用 Nuxt UI / Tailwind CSS 的语义 class 和组件 props。只有语义 class 不能表达状态强度时,才使用 bg-primary/15border-primary/40bg-elevated/50 等透明度微调。证据:electron.vite.config.tssrc/renderer/src/components/shared/UiSurface.vue
  • MUST 通过背景层级、间距、字体权重和有限边界建立结构,不依赖大面积渐变、重阴影或 hover transform。证据:src/renderer/src/layouts/AppLayout.vuesrc/renderer/src/pages/overview.vue
  • MUST 保持相同语义使用相同视觉模式,不为局部页面创造一次性样式。共享模式优先落到 src/renderer/src/components/shared/** 或现有布局组件。证据:src/renderer/src/components/shared/UiSurface.vuesrc/renderer/src/components/shared/AppEmptyState.vue

Design Tokens

  • MUST 保持 Nuxt UI 主题色为 primary: "teal"secondary: "cyan"neutral: "slate",除非先更新本规范和相关主题配置。证据:electron.vite.config.ts
  • MUST 优先使用语义颜色 class:页面/卡片表面使用 bg-default,框架区域使用 bg-muted/30,输入框和列表卡片使用 bg-elevated,默认边界使用 border-default/50,正文使用 text-default,弱信息使用 text-muted,标题使用 text-highlighted。证据:src/renderer/src/layouts/AppLayout.vuesrc/renderer/src/components/layout/AppHeader.vuesrc/renderer/src/pages/overview.vue
  • MUST 将 teal 作为状态强调色,用于主操作、当前流程、选中态和关键状态提示;不要把 teal 当作大面积品牌背景。证据:src/renderer/src/components/layout/ActivityBar.vuesrc/renderer/src/pages/settings.vue
  • SHOULD 使用 Tailwind 默认圆角:按钮、输入框、badge 使用 rounded-md;卡片和列表项使用 rounded-lg;modal/panel/大图标容器使用 rounded-xl;欢迎页或低密度展示区域可使用 rounded-2xl。证据:src/renderer/src/components/shared/UiSurface.vuesrc/renderer/src/components/shared/AppEmptyState.vue
  • MUST 使用 Tailwind 默认 spacing scale,不新增自定义 spacing token。默认节奏是同组元素 8px、组间 16px、页面区块 24px,低密度首屏可放大到 32px。证据:src/renderer/src/pages/overview.vuesrc/renderer/src/pages/integration.vuesrc/renderer/src/pages/settings.vue
  • MUST 使用 Nuxt UI / Tailwind 默认字体族;不要在 src/renderer/src/assets/main.css 中重设全局字体。代码、路径、命令片段可以使用现有 code / mono 样式。证据:src/renderer/src/assets/main.css

阴影与动效

  • MUST 让阴影只表达空间层级,不用于 hover 反馈。基础层和默认卡片使用 shadow-none,输入框或小浮层可使用 shadow-sm,modal、toast、command palette 可使用 shadow-lgshadow-xl。证据:src/renderer/src/components/shared/UiSurface.vuesrc/renderer/src/pages/overview.vue
  • MUST 禁止 hover 时的 scaletranslaterotateshadow 变化、bounce/spring、渐变、彩虹或发光动画;hover 反馈只改变颜色、背景或边界强度。证据:src/renderer/src/components/shared/UiSurface.vuesrc/renderer/src/components/layout/ActivityBar.vue
  • MUST 避免 transition-all,优先声明 transition-colors duration-150transition-opacity duration-200 等具体属性。证据:src/renderer/src/components/shared/UiSurface.vuesrc/renderer/src/components/layout/AppHeader.vue
  • SHOULD 使用短而稳定的过渡:颜色/背景/边框使用 duration-150,透明度或进入动画使用 duration-200;避免 duration-75 以下的闪烁和 duration-500 以上的拖沓感。

启动反馈

  • MUST 让静态 startup.html 与 Vue StartupLoading.vue 通过 src/renderer/src/assets/startup.css 共享轻量品牌语言:主题匹配的纯色背景、由生成图标裁切的点阵 Logo、FylloCode 字标和“正在启动…”状态文案;不得展示环形进度、Logo pulse、虚假的百分比、阶段文案或重型组件库。静态页面不得加载 renderer JavaScript,确保主 bundle 未准备好时仍可显示。
  • MUST 让静态 startup shell 的状态文案延迟 0.8s 出现,让正式 renderer index.html 在 Vue #app 内预置使用共享 stylesheet 的等价桥接 shell,并让 Vue overlay 的状态文案立即可见;文档切换时 MAY 重启点阵扫光相位,但背景、Logo 基底、字标和状态位置必须保持稳定,不得产生白闪、空容器、旧样式回退或布局跳动。
  • MUST 让 startup shell 与 Vue overlay 在浅色/深色主题下使用一致的视觉变量,并在 prefers-reduced-motion: reduce 时禁用点阵扫光和状态显现动画;正常动效只使用低频 opacity 变化,不使用 bounce、强发光、大面积渐变、旋转圆环或脉冲缩放。证据:src/renderer/startup.htmlsrc/renderer/src/assets/startup.csssrc/renderer/src/components/shared/StartupLoading.vue

布局层级

  • MUST 保持唯一全局 <main>src/renderer/src/layouts/AppLayout.vue 中。页面 slot 内不要再嵌套全局 <main> 或全局 <aside> landmark;分区使用 divnavsection。证据:src/renderer/src/layouts/AppLayout.vuesrc/renderer/src/pages/settings.vue
  • MUST 保持应用框架层级:AppHeader 使用 h-8.75 bg-muted/30 border-b border-default/50ActivityBar 使用 w-16 bg-muted/30 border-r border-default/50AppLayout main 使用 flex-1 flex p-2 min-w-0 bg-elevated;内容 shell 使用 rounded-lg bg-default overflow-auto。证据:src/renderer/src/components/layout/AppHeader.vuesrc/renderer/src/components/layout/ActivityBar.vuesrc/renderer/src/layouts/AppLayout.vue
  • MUST 让卡片化页面根容器使用 flex flex-1 overflow-hidden bg-elevated space-x-2,内部主内容卡片、侧栏卡片和事件栏卡片使用 rounded-lg bg-default overflow-auto。证据:src/renderer/src/pages/settings.vue
  • SHOULD 按信息密度选择内容宽度:多列概览和集成页用 max-w-6xl,中等密度任务页用 max-w-5xl,文本列表或 proposal 列表用 max-w-3xl,设置/表单用 max-w-2xl。证据:src/renderer/src/pages/overview.vuesrc/renderer/src/pages/integration.vuesrc/renderer/src/pages/settings.vue
  • MUST 使用 Tailwind 默认 breakpoint,不新增自定义 breakpoint;窄窗口和桌面窗口都不能出现无意义横向滚动。证据:src/renderer/src/pages/overview.vuesrc/renderer/src/pages/integration.vue

组件模式

  • MUST 通过 electron.vite.config.ts 中的 renderer.plugins.ui 做 Nuxt UI 全局样式覆盖;局部覆盖使用组件 ui prop 或 class;不要用外部 CSS 选择器覆盖 Nuxt UI 内部结构。证据:electron.vite.config.tssrc/renderer/src/components/layout/AppHeader.vue
  • MUST 让全局 overlay 通过 Nuxt UI theme 配置统一声明。UModalUSlideover overlay 使用 bg-black/45 dark:bg-black/60 fyllo-overlay-blurfyllo-overlay-blur 固定维护在 src/renderer/src/assets/main.css,不要在 theme 配置里使用 Tailwind arbitrary backdrop utility。证据:electron.vite.config.tssrc/renderer/src/assets/main.css
  • MUST 优先使用 UiSurface.vue 构建默认卡片。UiSurface 支持 asvariantinteractivepadding props;默认使用 rounded-lg bg-elevated dark:shadow-none,interactive 状态使用 hover:bg-accented。证据:src/renderer/src/components/shared/UiSurface.vue
  • MUST 保持可点击卡片 hover 只改变背景或边界强度,例如 hover:bg-accentedhover:bg-elevatedhover:border-primary/40;禁止 hover scale、translate 和 shadow 变化。证据:src/renderer/src/components/shared/UiSurface.vue
  • MUST 优先用 Nuxt UI props 表达按钮语义:主操作使用 UButton color="primary";次要操作使用 color="neutral" variant="outline";工具栏和 icon button 使用 color="neutral" variant="ghost";危险操作使用 color="error"。同一区域内避免多个并列 primary 按钮。证据:src/renderer/src/components/shared/AppEmptyState.vuesrc/renderer/src/components/layout/AppHeader.vue
  • MUST 让 icon-only 按钮具备 tooltip 或 aria-label,视觉图标不能是唯一可理解的状态说明。证据:src/renderer/src/components/layout/AppHeader.vuesrc/renderer/src/components/layout/ActivityBar.vue
  • MUST 让 Workspace destructive/repair overlay 明确区分可恢复删除与永久清理:soft delete 说明 tombstone 可恢复,永久删除使用 error action 和二次确认并声明实际清理边界,purging/cleanup-failed 只显示继续或重试;missing Folder 修复与历史 Session 影响确认必须保留 identity/path 摘要。证据:src/renderer/src/components/welcome/WorkspaceEditorModal.vuesrc/renderer/src/components/welcome/DeletedWorkspaceManager.vue
  • MUST 使用 AppEmptyState.vue 表达空状态,不使用纯文字空态。空状态必须包含图标、标题、描述和可选主操作;卡片内空态使用 compact。证据:src/renderer/src/components/shared/AppEmptyState.vuesrc/renderer/src/pages/integration.vue
  • SHOULD 让状态 badge 优先使用 variant="soft";进行中/活跃态使用 color="primary",归档/禁用使用 color="neutral",错误使用 color="error"。证据:src/renderer/src/components/acp/AgentKindBadge.vuesrc/renderer/src/components/task/TaskCard.vue

页面模式

  • MUST 让列表、看板、概览和侧栏导览类页面说明区优先使用 src/renderer/src/components/shared/PageHeader.vuePageHeader 只接受 eyebrowtitledescription 文案 props,不提供 slot 或局部 class、style、layout props;右侧状态或操作由页面级 header 布局组合。其视觉基准为 eyebrow text-[11px] font-medium uppercase tracking-wider text-primary-600 dark:text-primary-400、h1 text-xl font-semibold tracking-tight text-highlighted、description text-sm text-muted,头部和内容保持 gap-6space-y-6。证据:src/renderer/src/components/shared/PageHeader.vuesrc/renderer/src/pages/overview.vuesrc/renderer/src/pages/task.vuesrc/renderer/src/pages/specs.vuesrc/renderer/src/pages/guidelines.vue
  • SHOULD 不给沉浸式工作区、reader/detail 主内容面板或纯空状态页面硬补 PageHeader;这类页面可保留属于当前 pane 的局部 header 或直接使用 AppEmptyState.vue。证据:src/renderer/src/pages/chat.vuesrc/renderer/src/pages/workflow.vuesrc/renderer/src/pages/specs.vuesrc/renderer/src/pages/cron.vue
  • MUST 让设置类左侧垂直导航使用 w-65 bg-default rounded-lg;未选中项使用 hover:bg-elevated,当前项使用左侧 3px teal indicator 加 bg-primary/15 text-primary。证据:src/renderer/src/pages/settings.vue
  • MUST 保持 ActivityBar 只显示图标和 tooltip。按钮容器使用 size-10 rounded-lg,图标使用 size-5,激活态使用左侧 3px teal indicator 加 bg-primary/15 text-primary。证据:src/renderer/src/components/layout/ActivityBar.vue
  • MUST 保持 AppHeader 的 35px 高度和三栏布局。项目切换器使用 pill 形态和 bg-elevated hover:bg-accented transition-colors,右侧 icon button 使用 size-6 容器和 size-4 图标,并保留 -webkit-app-region: drag / no-drag 分区。证据:src/renderer/src/components/layout/AppHeader.vue

文案与可访问性

  • MUST 让 UI 文案精确、直接、无填充词。操作按钮使用“动词 + 对象”,错误信息说明“发生了什么 + 下一步怎么做”,危险操作确认按钮复述动作对象而不是只写“确认”。
  • MUST 将 Workspace 领域模型与用户呈现术语解耦:内部 kind: "folder" 的顶层对象对用户称为 Project,内部 kind: "collection" 的顶层对象称为 Workspace,即使 Collection 只有一个成员也不得改称 Project;Workspace member、repository owner、筛选 owner 和 automation target 中的内部 Folder 对用户统一称为 Project。该规则只约束最终用户文案,不重命名 WorkspaceKindFolderMetafolderId、IPC/schema、storage、migration 或 Agent/MCP contract。证据:openspec/specs/workspace-presentation-terminology/spec.mdsrc/renderer/src/utils/workspace-presentation.ts
  • MUST 在语义指向 filesystem path、选择器、missing 或 relocation 时使用“项目目录”,不得把 Project identity 与当前 path 等同;同时覆盖 Project 和 Workspace 的列表、switcher、回收站或未知 kind 场景必须使用中性表达,不能用内部 Workspace 上位概念把 Project 误称为 Workspace。
  • MUST 让 kind-sensitive UI 复用 src/renderer/src/utils/workspace-presentation.ts 的呈现函数和术语原子,不得在页面或组件中复制 kind 判断与核心名词映射。Cleanup state 和结构化 Workspace/Folder 错误必须先经过呈现边界;raw enum、Main 内部 message 与诊断术语不得承担主要用户说明。
  • MUST 以对象语义和 UI sink 审查未来文案,而不是维护完整句子的允许清单。确属 Agent-facing、协议或诊断的 renderer 字符串可保留内部术语,但必须通过带理由的显式 lint 声明标记非用户语境,不得按文件关闭术语门禁。
  • MUST 让 toast 只说明具体发生的变化,避免泛化“成功”文案;进行中状态中文使用“正在 + 动作 + …”,英文使用 present participle + ;省略号使用 ,不要使用 ...
  • MUST 保留技术名词、命令、路径、agent 名称和 proposal ID,不翻译或美化;必要时使用代码样式。
  • MUST 保持状态不只靠颜色表达,badge、错误、警告、成功和进行中状态必须有文字,必要时再配合 icon;普通工具状态除外:运行中使用 shimmer、完成态使用稳定标题、失败态使用 error icon,四态均无 suffix,错误文本保留在 Error 详情中。
  • MUST 保留可见焦点。Nuxt UI 交互组件优先使用默认 focus-visible;自定义 focusable 元素必须提供可见焦点,例如 focus-visible:outline-2 focus-visible:outline-primaryfocus-visible:ring-2 focus-visible:ring-primary/30
  • SHOULD 依赖 Nuxt UI 语义 token 的默认对比度;手写 palette 或透明度组合时,普通正文对比度应满足 WCAG AA 4.5:1,大号文字、图标和关键边界至少满足 3:1

示例

  • src/renderer/src/components/shared/PageHeader.vue:共享页面说明区的 eyebrow、标题和描述文案结构。
  • src/renderer/src/components/shared/UiSurface.vue:共享卡片 surface 的默认视觉和 interactive 状态。
  • src/renderer/src/components/shared/AppEmptyState.vue:共享空状态结构、图标层级和可选主操作。
  • src/renderer/src/components/layout/ActivityBar.vue:全局导航的图标、tooltip、active indicator 和状态颜色。
  • src/renderer/src/components/layout/AppHeader.vue:窗口 header、项目切换器、icon-only button 与 drag/no-drag 区域。
  • ❌ 在业务组件里重复定义 UModal / USlideover overlay 样式,或通过外部 CSS 选择器覆盖 Nuxt UI 内部结构。
  • ❌ 用 hover:scale-*hover:shadow-*transition-all 或大面积渐变表达普通 hover 状态。

验证

pnpm exec vitest run --project renderer
pnpm typecheck:web

视觉类改动还应人工检查浅色/深色主题、窄窗口和桌面窗口,重点看 overlay、focus-visible、空状态、ActivityBar、AppHeader、设置页侧栏和列表页 header;普通工具状态还应同时检查 pending/in_progress shimmer、completed 稳定标题、四种状态均无 suffix,以及 failed 的 error icon 与可展开 Error 详情。

失效信号

  • electron.vite.config.ts 的 Nuxt UI theme、src/renderer/src/assets/main.csssrc/renderer/src/layouts/AppLayout.vuesrc/renderer/src/components/layout/**src/renderer/src/components/shared/**src/renderer/src/pages/** 或 Tailwind / @nuxt/ui 版本发生变化时,重新检查本文档。