Files
fkysly 451fbd3bc3 fix(client): the diagnostics badges were painted with an ink token (#731)
`--dsw-alias-brand-primary` is an INK colour: the host resolves it to #0f1115
in the light theme and to #f9fafb in the dark one, and uses it for text and
strokes while the surface underneath is a different token. The market had it as
a badge *background* with a hardcoded `#fff` label, so in dark mode on 0.1.7 the
fill and the text were both #f9fafb — white on white. The bundle "official"
badge and every row of the override list rendered as empty white pills, which is
what the report showed; the numbers were still there, invisible.

Verified on a real 0.1.7-rc.2 host, both themes, computed styles:

- before: `ovByTag` / `diagBadgeOfficial` bg rgb(249,250,251), colour
  rgb(255,255,255) — identical channels, nothing to read
- after: dark bg rgb(249,250,251) colour rgb(15,17,21); light bg
  rgb(15,17,21) colour rgb(255,255,255)

The host's own filled pair is `button-primary-fill` + `label-primary-foreground`
(its primary Button and Pill use exactly that) — both with the old pair as the
fallback, so hosts that predate those tokens are unchanged. The same sweep found
four more surfaces hardcoding white on a themed fill, and the avatar letter that
was white on `bg-layer-2` — which is white in the light theme.

`tests/style-tokens.spec.ts` keeps it from coming back: no rule may set a
themed background and a literal text colour together. Deliberately not checked:
an ink token *as* a background — that is the correct fill for a progress bar and
for the 9% tints the market already uses.
2026-09-26 00:57:42 +08:00

5.6 KiB
Raw Permalink Blame History

AGENTS.md — 产品设计原则

这份文档是约束,不是参考。市场里的任何产品设计、功能设计、界面改动,先按这里过一遍。 代码规范见 TESTING.md,安全边界见 SECURITY.md;这里只管一件事:给普通用户做的东西。


一、三条根本原则

1. 自然 —— 从用户的意图出发,不从实现出发

用户是带着一件事来的(「我想让 DSH 能发通知」),他不知道也不需要知道系统内部怎么分工。 界面要顺着他的意图走,不能要求他先理解我们的模型(插件 / bundle / profile / 层 / 依赖树)才能用。

  • 用户要做的事 → 一步就是一步,别为了对应内部结构而拆成三步。
  • 界面上出现的概念,必须是用户已有的概念。新造的词只有在无法避免时才出现,且第一次出现就要用人话解释。
  • 系统的复杂度由系统吸收:排序、格式化、本地化、缓存、降级、重试,都是我们的事,不是让用户去选。

2. 好理解 —— 说人话,别让用户猜

  • 用日常词:不说「凭据」「解析依赖」「幂等」「实例」「装载」,说「密钥」「准备依赖」「重复执行也没问题」「本次运行」「加载」。
  • 一句话说一件事;按钮 2–4 字;正文一句不超过 20 字。
  • 每一处文案都要能回答「所以呢?」——说完现象要说后果,说完后果要说下一步。
  • 报错必须是三件事:发生了什么、为什么、现在怎么办。只有错误码、只有「失败了」而没有出路的,都不合格。
  • 不确定就说不确定。宁可说「不知道」,也不要用一句听起来合理的话把空缺填上。

3. 面向普通用户 —— 替他做决定,而不是把决定推给他

  • 默认值就是产品:绝大多数人不会改设置。默认要选那个「不读文档也对」的。
  • 不把判断责任推给没有能力判断的人:给用户看的要么是他能行动的,要么是让他放心的,不能是「你自己看着办」。
  • 常态安静,罕见才打扰(渐进披露):
    • 大多数情况下都会出现的信息,是陈述,不是警告;
    • 只有在罕见并且用户此刻必须做点什么时,才允许变醒目;
    • 一个随处可见的警告,训练出来的是「不看警告」——包括真出事的那一次;
    • 高级/专业信息默认收起,但可发现:需要它的那一刻能找到,不需要的时候不占位置。
  • 不替用户做无谓的确认:可撤销的动作直接做,配一个撤销;只有不可撤销、或有真实后果的动作才打断他,并且说清后果。
  • 反馈与确定性:每个动作都要有即时反应和明确落点(成功 / 失败 / 去哪看)。「点了没反应」是最差的状态。

二、苹果那套做法,落到这个项目的可检验规则

苹果的产品哲学里真正有用的是几条很朴素的判断,下面每条都写成本项目能检查的形式:

原则 在本项目里意味着
看不见的复杂度 用户不该看到内部模型;需要暴露时,先翻译成他的语言
直接操作 一个动作一个结果;不要为了「安全」加一层只有开发者懂的中间态
渐进披露 常态安静、罕见打扰、高级可发现(见上)
少即是多 「要不要加这个信息」的默认答案是不加;能去掉的先去掉
一致性 同一个概念全篇同一个词;同一个控件同一个行为;同一份事实在不同卡片上用同一段渲染
恰当 语气跟场合走:出错时克制并给出路,成功时简短,危险操作时严肃
细节即产品 空状态、错误状态、深浅色、窄屏、长文本、加载中——都是要设计的界面,不是边界情况
不为不可能的错误设计 不要为了理论上可能的情况,给所有人加步骤

三、动手前先问自己(验收清单)

  1. 这句话,一个不懂技术的用户能读懂吗?读不懂的替换成日常词。
  2. 这条信息他看完能做什么?不能行动、也不能让他放心的,就不进主流程。
  3. 这个提醒是常态还是罕见?常态 → 降级为陈述。
  4. 这个确认能撤销吗?能撤销就别问。
  5. 这个功能默认展开还是收起?普通用户真的需要默认看到它吗?
  6. 出错了之后他知道下一步吗?
  7. 深浅色、窄屏、空列表、加载中、失败态,都过了一遍吗?
  8. 中英两份文案说的是同一件事吗?

四、已经犯过、不要再犯

这些是本项目真实发生过并修掉的,写在这是为了不再重演:

  • 把常态渲染成警告:目录里 483 条「红色提示」中 354 条是同一句「同时读凭据并联网」——插件调模型本来就要用 key,把它标黄的结果是用户学会无视这一行。
  • 把能力清单挂在每张卡片上:列表里没人靠「会读文件」挑插件;它的位置在详情页,且默认收起。
  • 让用户读到系统内部:卡片上直接显示 uses literal IP 198.18.0.0 for network access;诊断页显示 bundle、profile、disable-carrier。
  • 只有现象没有出路:Error: fetch failed(真实原因在 cause 里)、「操作失败」而不说重试。
  • 把「没查到」说成「没问题」:未检出 要写成「没有扫描到。这不等于安全。」
  • 同一句标签重复铺满:每行前面都加「值得看一眼:」。
  • 为不可能发生的错误加步骤:装前用一屏能力清单拦人,而其中没有一条是用户能采纳的。