UI 一致性审查
这是针对 apps/web 的样式把关,不是全面审查。只审查 diff 中改动的行,并回答三个问题。不要构建项目,不要检查生成出来的 CSS,不要在代码库里追踪选择器的使用方,也不要索取截图。如果 diff 没有让违规变得一目了然,就不存在发现。
1. 共享基础组件优先于自定义控件
产品 UI 必须使用 apps/web/src/components/ui 中的基础组件(Button、Input、InputGroup、Select、Toggle、Menu、Dialog、Tooltip、ScrollArea,以及该目录中的其余部分),而不是重新做一套。
- 当对应的基础组件已经存在时,如果把原始的
<button>、<input>、<select>或<textarea>做成控件的样子,应予标记。 - 如果调用处用自己的类字符串覆盖基础组件的高度、圆角、内边距、焦点环或基础色,应予标记。若多处需要同样的外观,修法是在基础组件上新增尺寸或变体。
- 不要标记那些有意不用基础组件的原始元素:语义行、标签页、缩放手柄、色板、编辑器表面,以及任何行为或几何按设计就不同的东西。
2. Tailwind 写在所属组件里,而不是全局 CSS
样式以 Tailwind 类的形式写在渲染该元素的组件里。
- 如果同样的样式可以写成所属组件上的 Tailwind 类,却往
apps/web/src/index.css或任何其他.css文件里新增规则,应予标记。新的全局 CSS 仅当 Tailwind 无法在所属处表达时才可以接受:生成的 Markdown 或命令式 DOM、自定义元素与 shadow root、动画、运行时主题变量,以及浏览器或 Electron 集成。 - 如果新的
style={{ ... }}对象或行内<style>块携带已有 Tailwind 类能够覆盖的静态值,应予标记。运行时算出的动态值没有问题。 - 如果只服务于主题的声明使用原始的
.dark选择器,而不是@variant dark/@variant light,应予标记。
3. 可组合组件
本代码库期望的 UI 构建方式,以 apps/web/src/components/chat/ 中的 Composer(编写器)横幅系统为参照:
ComposerBanner.tsx导出一个由小型插槽组件构成的对象(Root、Row、Icon、Content、Actions、Dismiss、Children,等等)。每个插槽拥有自己的 Tailwind 类,暴露data-slot属性,接收className并展开其余 props,同时使用cn,让调用方可以调整而不必覆盖。变体和密度是Root上的 props,而不是调用处临时拼凑的类字符串。插槽需要真正的控件时,渲染Button(来自ui/),而不是经过样式化的<button>。ComposerBannerStack.tsx把这些插槽组合成有序的堆叠,并且只负责堆叠行为(优先级、展开与收起、关闭时的过渡)。ComposerPlanFollowUpBanner.tsx这类使用方只有几行<ComposerBanner.Row><ComposerBanner.Icon/><ComposerBanner.Content>…,并且只给自己的内容加样式。
新增和改动过的 UI 都要符合这个形态:
- 如果新组件复制现有基础组件的一段标记和类,而不是去组合或扩展它,应予标记。
- 如果共享组件上出现一大段一次性的类字符串,而另一处调用显然已经用了同样的处理,应予标记。修法是在共享组件上增加变体或新插槽。
- 如果新的 Composer 横幅或提示绕过
ComposerBanner插槽,自行拼装它的行、图标列或操作区,应予标记。
报告
只报告由改动行引入的违规。每一条都在相关行上发表一条简短的行内评论:指出规则,指出代码应当改用的基础组件或位置,然后停止。不要评论类的排列顺序、审美偏好或未改动的遗留代码,也不要要求清理拉取请求(pull request)范围之外的内容。
没有发现时,整段最终回复必须恰好是单独一行的 All clear,除此之外不要有任何内容。