makecindy / makecindy/cindy

排版治理:字重四档收编 + 字号白名单归一 + 桌面守卫与豁免登记

Open
#1,505 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 背景

对照 `docs/design-rules/DESIGN.md` §3 做了一次全仓字重/字号走查(2026-08-03,方法论来自 MivoCanvas 排版治理实战)。结论:**规范存在但桌面端没有守卫,已实际漂移**;手机端 2026-07 已完成同款收敛且有守卫测试(`typographyTokenDiscipline.test.ts`),`packages/*` 零命中。本 issue 固化目标规则、问题清单、豁免登记与 PR 拆分,只治理桌面端 + 文档。

### 现状直方图(apps/desktop)

字重(Tailwind class):`font-medium`(500)×1022、`font-normal`(400)×98、`font-semibold`(600)×73、`font-bold`(700)×11、`font-extrabold`(800)×1。
字号:token 类 `text-N` 约 1600 处(高频档 12/13/11/14);任意值 `text-[Npx]` 约 550 处(含 22 处小数、8 处 <10px);语义类 `text-xs/sm/base/lg` 452 处。
`tailwind.config.ts` 的 fontSize 梯子当前是 9–28 **每个整数全开**,其中 9/19/21/22/23/25/26/27 零使用。

## 已拍板决策(2026-08-03,拍板人 = 用户)

1. **字重四档收编**:token 梯 400/500/600/700(与手机端 `apps/mobile/src/theme/tokens.ts` 的 fontWeight token 完全一致)。UI chrome 工作集为 400/500/600;**700 只允许经登记豁免域出现**(见下表),800 清零。600 收编后现存 73 处 `font-semibold` 合法化、无需改动。
2. **字号"只归写法、不动数值"**:本轮不做字号档位迁移,只做小数吸附、<10px 提升到下限、任意值归 token 写法、config 删未用档。白名单见下。
3. **`LegacyMigrationDialog` 裁决**:字号 23/19/17 修掉(按缩放画布算出的值,吸附回白名单);字重 700 归登录品牌域豁免。

## 目标规则

### 字重(全站)

| 档 | 用途 |
|---|---|
| 400 | 长文正文、代码 |
| 500 | UI 默认强调、标题 |
| 600 | 限量强调(现 semibold 存量收编) |
| 700 | **仅限豁免域**:markdown ``、hljs 主题移植、登录品牌画布 |

CJK 注记:桌面未设 `font-synthesis: none`,PingFang 公开档位到 600,UI 里 700 会触发中文伪粗体——**中文层级不得依赖 600 vs 700 区分**,此条写入 DESIGN.md。

### 字号白名单(桌面 UI)

- UI 段:{10, 11, 12, 13, 14, 15, 16}
- 标题/内容段:{18, 20, 24, 28}
- 语义类 `text-xs / text-sm / text-base / text-lg` 收编(等值映射,紧凑模式已有适配),**禁止新增任意值 `text-[Npx]` 与一切小数**。
- 品牌画布域(login / oauthResultPage,设计 px 坐标系)不映射本白名单,等同手机端 `loginSkinLayout.ts` 的地位:字面量只许进画布常量文件,组件消费端照常受守卫扫描。

## 问题清单与处置

### A. 字重(PR2,~15 处)

- [ ] `font-bold` ×11 逐处裁:普通 UI chrome 降 600/500;登录域(`LoginControls.tsx` 等)保留并登记
- [ ] `font-extrabold` ×1:`src/renderer/features/cc-agent/CCAgentSidebarUpper.tsx:3367`(同行还有 `text-[12.5px]`,双违规)→ 归 600
- [ ] `FileBrowserBody.css:98,103,108` 的 `font-weight: 600 !important` ×3:核实 !important 必要性,值合法化后清理写法
- [ ] `src/preload/browserCommentPreload.ts:386` 的 `font: 600 12px/22px ...` shorthand:拆开写;600→500 或登记(注入外部网页的 UI,用系统字体属合理分歧,需登记)
- [ ] `apps/mobile/src/session/mermaidWebViewHtml.ts:112` 的 `font-weight: 700`(手机端已登记盲区内唯一越档处)→ 归 500/600

### B. 字号(PR3)

小数吸附(22 处,向下吸附):
- [ ] `text-[12.5px]` ×15 → text-12(`ModelSelector.tsx` 独占 10 处)
- [ ] `text-[11.5px]` ×3 → text-11;`text-[10.5px]` ×2 → text-10;`text-[13.5px]` ×1 → text-13
- [ ] `text-[8.4px]` ×1(`ModelSelector.tsx:170`,dense 模式,同族还有 `h-[14.2px]` 等小数盒子一并核)→ 10px

<10px 提升(8 处):`text-[9px]` ×7(`RolePillDropdown.tsx:131`、`ReviewTabBody.tsx:1530,1576`、`UsageDailyBars.tsx:194`、`MessageNavRail.tsx:407`、`GhostPluginPage.tsx:1642` 等)+ 上述 8.4 → 10px,目检徽标不挤。

白名单外孤档(8 处,逐处吸附):
- [ ] `text-17` ×4:`VoiceInputSection.tsx:2623,2631,2645`(统计数字)、`CreateWorkerPopover.tsx:636`(标题)→ 16 或 18,目检定
- [ ] `LegacyMigrationDialog.tsx:132,145,173` 的 23/19/17 → 24/18/16(±1px 内吸附,目检确认)
- [ ] `EmptyState.tsx:48` 的 `text-[22px]` → 20 或 24

写法归一 + config 收紧:
- [ ] 任意值 `text-[Npx]`(整数,~530 处)机械替换为 `text-N` token 类。**已知行为变化**:doc 紧凑模式(`.chat-rail-compact`)对任意值不缩(如 `text-[11px]` ×106 目前漏缩),归 token 后开始 -1px——方向是修复不一致,替换前后紧凑栏截图对比确认
- [ ] `tailwind.config.ts` fontSize 删除零使用档 9/19/21/22/23/25/26/27,只保留白名单档

### C. 守卫(PR4)

- [ ] 桌面新增 vitest 守卫(蓝本 = 手机 `typographyTokenDiscipline.test.ts`),进 `pnpm test:unit` 提交门禁。覆盖:Tailwind 字重类白名单、`text-[Npx]` 任意值禁令、内联 style 的 fontSize/fontWeight 字面量、JS 注入字符串(preload / main 生成 HTML)中的 font-weight/font-size、`font:` shorthand 禁令(只许 `font: inherit`)
- [ ] 豁免四元绑定:文件 + 允许值 + 理由注释 + 期望命中次数
- [ ] `tailwind.config.ts` fontSize 档 ↔ DESIGN.md 白名单镜像检查
- [ ] 红绿 fixture;显式登记盲区清单(反射拼接、跨文件常量等,写进测试头注释)

### D. 文档(PR1)

- [ ] DESIGN.md §3 修订:字重 400/500 双档改为上表四档 + 700 豁免域条款(同步修改 124/280/330 行三处"never bold"表述);补 UI 字号白名单(解决 §3 Hierarchy 表偏品牌面、与 app chrome 实际两张皮的问题);补 CJK 伪粗体注记
- [ ] 豁免登记表(下表)入文档
- [ ] non-goals 登记

## 豁免登记表(初稿)

| 域 | 范围 | 允许 | 理由 |
|---|---|---|---|
| 登录品牌画布 | `LoginControls.tsx`、`loginDesignTokens.ts`、`LegacyMigrationDialog.tsx`(仅字重)、`oauthResultPage.ts` 品牌块 | 700 + 设计 px 字号 | DESIGN.md §16 已登记 Bold,figma 画布坐标系 |
| markdown 内容 | ``(Tailwind preflight `bolder`) | 700 | 用户内容语义,非 UI chrome |
| hljs 主题移植 | `globals.css` 内 hljs 规则 ×4 | `bold` | 第三方主题移植,保真优先 |
| 外部页注入 | `browserCommentPreload.ts` | 系统字体族 | 注入他人网页,不强加 Inter;字重待 PR2 裁 |
| 手机 WebView HTML 生成器 | `selectableMarkdownHtml.ts` 等 | CSS 语法字面量 | 手机守卫已自登记盲区,值需守纪律 |
| 紧凑模式派生值 | `globals.css` `.chat-rail-compact` 段 | calc/-1px 派生 | 机制本体 |

## Non-goals(本轮明确不做,防止后人当漏网)

- line-height 治理(桌面 `leading-[1.45]` ×20、`leading-[1.55]` ×9 等混轨漂移,已知、暂缓)
- 语义类 `text-xs/sm/base/lg` → `text-N` 的机械统一(452 处,等值改写零收益,收编即可)
- 手机端(已收敛)与 `packages/*`(零命中)
- letter-spacing / font-family 治理

## PR 拆分与顺序

| # | 内容 | 依赖 |
|---|---|---|
| PR1 | DESIGN.md 立法(梯子/白名单/豁免表/CJK 注记/non-goals) | — |
| PR2 | 字重归一(清单 A,~15 处) | PR1(设计依据) |
| PR3 | 字号归一(清单 B;若嫌大可把"任意值归 token"单拆) | PR1 |
| PR4 | 守卫 + 镜像检查 + 红绿 fixture | PR2、PR3 合入后 |

每个 PR:DCO 签名、`pnpm test:unit`、desktop typecheck、涉 UI 者按模板写设计依据(引 PR1)。PR3 需附紧凑模式与徽标类目检截图;双模式(Light/Dark)不涉及颜色,无额外适配。

## 验收标准

1. 桌面守卫绿:白名单外字重/字号零命中,豁免命中次数与登记一致
2. `rg 'text-\[[0-9.]+px\]'` 在 `apps/desktop/src` 无小数、无白名单外整数命中(豁免域除外)
3. `tailwind.config.ts` fontSize 档与 DESIGN.md 白名单一致(镜像检查绿)
4. 紧凑模式截图对比确认无回归、徽标类 10px 目检通过

Contributor guide

Open the contributing guide

Research direction

Start with docs/design-rules/DESIGN.md §3 and the PR split, then inspect apps/desktop, tailwind.config.ts, and the named typography violations. Use the mobile typographyTokenDiscipline.test.ts as the guard blueprint and run pnpm test:unit. Done means the desktop whitelist and exemptions are enforced, the documentation and config mirror each other, and the listed UI checks pass without regressions.

Written by the indexing model from the issue text.

Assessment

Tech stack
tailwindcss, typescript
Domain
design, desktop, documentation, frontend, testing
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.