每个界面原语只有一个源头
上级:structure
十二道闸门,一条学说:每一个视觉原语只有一份定义,再由一道构建期闸门让第二份不可能存在。 这个产品的视觉一致性真正来自这里 —— 不来自风格指南,也不来自评审。
每一道闸门都写在同一个发现之后,而那个发现的形状总是同一个:这不是"某几处漏改",而是没有这一层,于是每个面各自决定它长什么样。
| 闸门 | 规矩 | 当初发现了什么 |
|---|---|---|
check-one-select | 全 app 一个下拉,在 SelectField 里 | 19 个 <select> 有五种互不知道的写法 —— 盒子边框 / 小盒子 / 下划线 / sm-field-input / gate 那个近黑实心(全页最重的色块) |
check-one-text-input | 一种长相,源头是 .sm-field-input | 同一种控件长了两张脸:连接器凭据 / op 参数 / SEO 是整框;codes 新建弹窗、简历 composer、gate、AI provider 面板是下划线。owner 隔一屏就换一套标准 |
check-one-time-format | 时间三种写法,全在 lib/ui/format-time.ts | 一次会话里出现三种 —— 8/8/2026, 10:16:07 AM(美式 locale + 秒 + AM/PM)、2026-08-07T01:09:14Z(ISO+Z,给机器看的)、同一页上的 last refresh · now |
check-one-scrim | 模态遮罩只有一个来源 | 四条 *-overlay 规则各写一份 color-mix(…) 字面量。四份谁也不知道彼此存在:调其中一处,另外三处悄悄分叉——而分叉不会报错,只会让某些模态压得住底层、某些压不住 |
check-one-layer-scale | 层级只在一处声明 | "谁在谁上面"这件事读不出来:19 处层级散在两种语言里 —— CSS 九个魔数、TSX 十个工具类,没有任何一处声明这些数字的顺序含义。而"模态遮罩"这一件事本身就有三个不同的 z |
check-one-empty-state | admin 的列表空态只从 ListPane 出来 | 每个 section 自己写 list.length === 0 ? <空态/> : <列表/> —— 这句话只有两种结局,而真实世界有三种:拉失败之后列表也是空数组,于是失败穿上了空态的衣服 |
check-one-section-heading | 一节的标题只从 AdminSectionHead 出来 | —— |
check-one-corpus-href | 一条语料的公开地址只有一个来源 | 15 处各自现拼且互相不一致;体裁名被当成了路由名,于是一条 writing 的引用在生产上 404(corpus) |
check-sm-class-defined | 写进 TSX 的每个 sm-*,CSS 里必须真有 | 一个"看起来很像"的类名渲染不出任何东西,也不报任何错 |
check-no-computed-class | Tailwind 任意值方括号里不许插值 | w-[${n}px] 生成零 CSS,没人报错。有四处"名字说它在表达某个量、实际是常量" |
check-no-native-file-input | 选文件的按钮必须是这个产品画的 | <input type="file"> 自己画一个 Choose File / No file chosen,长相由操作系统决定 —— 跟奶油纸 + 朱红 + mono 那套语言毫无关系。在连接器弹窗里它是整扇窗唯一没被设计过的控件,就贴在被设计过的按钮旁边 |
check-peek-signals-more | 会被切的预览卡,切口处必须有续读信号 | summarize 的报告卡是有意的 sneak-peek(内层 iframe 写死 280px),但切口原本没有任何信号:正文断在句子中间撞上卡片边框,读起来像"坏了"而不是"还有" |
为什么是闸门,不是风格指南
风格指南是建议,由"还记得它存在"的那个人去查。上面每一条都是在分叉已经上线之后才写的,而且多数分叉在评审里是看不见的 —— 五种下拉,一次看一个文件,每一个都挺好。真正要紧的性质不是"我们对齐了一种长相",而是第二种长相没有地方可住。
也要说清这些闸门不是什么:它们不评判一个设计好不好。它们只强制"一个决定一旦做出,就只有一个家"(mechanical-guardrails,跟后端 convergence-inbound-and-outbound 是同一个动作)。品味仍然是人的问题;多份拷贝不再是。
代价,如实说
粒度不对的闸门会挡掉能工作的行为:修"提供了一个做不到的动作"时,如果规则比那个动作更粗,就会造出"连做得到的那个动作也一起拿掉了"—— 而 CI 全程绿着,因为闸门被满足了。所以每加一道闸门要问的不只是它禁了什么,还有它禁掉的东西里有没有我还想要的。