Design System

交互模式与行为规范

交互模式与行为规范

版本 1.0 - 从 v3 原型提炼的可复用模式。

1. 数据可视化注释

所有内嵌 viz 必须携带上下文锚,否则它只是装饰而非信息。

1.1 规则

  • 每个 viz 下方必须有 .viz-note 行(9px mono 字体,tertiary 色)。
  • Sparkline 注释说明 X 轴含义和节点语义。例:周一 → 周五 · 每个节点 = 1 条新机会
  • 进度环注释说明目标和预计完成条件。例:目标 100% · 预计 2 次阅读块完成
  • 条形图注释使用图例格式:- 计划线 - 超支 - 正常,每个图例项含色块 swatch。
  • 注释不参与 hover 交互,纯信息展示。

1.2 Token

--component-viz-note-font-size: 9px;
--component-viz-note-color: var(--color-text-tertiary);
--component-viz-legend-swatch-width: 8px;
--component-viz-legend-swatch-height: 2px;

2. Lazy View 注入

非首屏视图使用 <template> 标签存储 HTML,首次切换时 clone 注入。

2.1 流程

  1. 用户点击导航 → switchView(view) 调用。
  2. 检查 injectedViews Set:若未注入,先渲染 skeleton。
  3. 280ms 后从 #tpl-{view} clone content 注入到 #view-{view}
  4. 绑定事件(bindViewEvents):data-detail 点击/键盘、data-view-jump、reveal observer。
  5. 添加 .in 类触发 reveal 动画。

2.2 Skeleton 规格

  • 2 行 .sk-line(w40 + w80)模拟标题。
  • 1 行 .sk-line.w60 模拟副标题。
  • 2 个 .sk-block 模拟卡片。
  • Shimmer 动画 1.4s infinite。

2.3 性能考量

  • Today 视图 inline 渲染(首屏关键路径)。
  • 其他 7 个视图 template 存储,减少首屏 DOM 解析量。
  • 注入后 template 内容不再需要,但保留在 DOM 中(clone 不影响原 template)。

3. 键盘导航

3.1 Focus Stack(优先事项列表)

  • role="listbox" + 每个 item role="option" + aria-selected
  • ArrowDown / ArrowRight:选中下一项并触发 click(更新 inspector)。
  • ArrowUp / ArrowLeft:选中上一项。
  • Enter / Space:同 click。
  • 循环:到末尾后回到首项。

3.2 Detail Drawer Focus Trap

  • 打开时记录 previousFocus = document.activeElement
  • 打开后 50ms 将焦点移到关闭按钮。
  • Tab 循环:最后一个 focusable → 第一个 focusable。
  • Shift+Tab 循环:第一个 focusable → 最后一个 focusable。
  • 关闭时 previousFocus.focus() 恢复焦点。

3.3 全局快捷键

快捷键 行为
⌘K / Ctrl+K 打开 Command Palette。
Escape 关闭所有 overlay + detail drawer。

4. Inspector 同步

4.1 视图级默认上下文

每个视图在 viewInspectorMap 中定义默认 inspector 数据:

  • 可以是 inspectorData 中已有 key 的字符串引用(如 today → "renewal")。
  • 可以是内联对象(如 knowledge → {title, body, links, level, reason})。

4.2 切换行为

  1. switchView() 末尾查询 viewInspectorMap[view]
  2. 若为字符串:直接用该 key 的数据。
  3. 若为对象:注册到 inspectorData["__view_"+view] 并使用。
  4. 触发 140ms cross-fade swap 动画。
  5. 更新 currentInspectorKey 以支持"打开详情"按钮映射。

4.3 Debounce

快速连续切换视图或 focus-item 时:

  • 若上一次 swap timer 未结束,清除 timer 直接更新内容(不重播动画)。
  • 避免 cross-fade 互相打断产生闪烁。

5. 决策流反馈链

用户在 DetailDrawer 中做出决策后,以下 6 个位置必须同步更新:

  1. Detail state badge - 状态文字 + 注释更新。
  2. Detail timeline - 新条目 unshift 到顶部。
  3. Decision result panel - spring 弹入显示决策摘要。
  4. Today 卡片 - 标题 + 描述 + meta 更新 + .flash 动画。
  5. Inspector - 标题 + 描述更新(通过 applyInspector)。
  6. Audit events - 新审计条目插入 Governance 审计列表顶部。
  7. Toast - 底部弹出确认通知,3.4s 自动消失。

5.1 Card Flash 动画

@keyframes cardflash {
  0% { background: var(--color-accent-subtle); }
  100% { background: var(--color-bg-raised); }
}

触发方式:移除 class → void offsetWidth(强制 reflow)→ 添加 class。

5.2 取消操作门控

取消属于外部写操作,必须经过 ConfirmDialog:

  • 显示动作、影响对象、执行状态、自动化等级。
  • 用户确认后才执行 recordSubscriptionDecision("cancel")
  • 原型中只记录决定,不调用外部服务。

6. 主题切换

6.1 实现

  • 点击 toggle 按钮 → 检测当前主题 → 设置 data-theme 属性。
  • 添加 .theming 类 420ms,让所有颜色属性平滑过渡。
  • 过渡属性:background-color, border-color, color, box-shadow, background

6.2 暗色模式特殊处理

  • Grain 纹理从 noise SVG 换为 dot pattern(更干净)。
  • Wash 饱和度提高(accent glow 型渐变而非白色 wash)。
  • 阴影换为纯黑基底(更深的 depth 感)。
  • Accent 色提亮到 #7db89d 保持可读性。

7. Scroll Reveal

7.1 规则

  • .reveal 类元素默认 opacity: 0; transform: translateY(16px)
  • IntersectionObserver(threshold 0.12)检测到可见时添加 .in
  • .in 触发 600ms smooth easing 过渡到 opacity: 1; transform: none
  • 一旦 reveal 完成,unobserve 不再重复触发。
  • 视图切换时手动为当前视图所有 .reveal 添加 .in(因为已在视口内)。

7.2 与 Stagger 的关系

  • Stagger 用于视图内首屏元素的入场编排(animation-delay 递增)。
  • Reveal 用于滚动后才进入视口的 section。
  • 两者不冲突:stagger 是 CSS animation,reveal 是 CSS transition。

8. 脉冲点(Live Indicator)

用于表示"系统运行中"或"当前进行中"。

  • 8px 圆点 + ::after 伪元素做扩散环。
  • @keyframes pulse:scale(.5) opacity(.8) → scale(1.25) opacity(0),2.4s infinite。
  • 使用场景:sidebar footer 同步状态、hero chip、agenda 当前项、timeline 节点。

9. 响应式降级

组件 桌面 平板 移动
Inspector 固定右栏 隐藏 点击 focus-item 时打开 detail drawer。
Sidebar 固定左栏 缩窄 Fixed drawer + hamburger。
Signal grid 3 列 2 列(末项跨列) 1 列。
Coverage 6 列 3 列 2 列。
Focus item 3 列 grid 2 列(meta 移到第二行)。
Detail drawer 768px 100vw。