makecindy / makecindy/cindy

refactor(theme): text-secondary / text-tertiary 语义与强弱倒置,建议走「交换名字」而非「交换值」

Open
#2,559 1 comment 0 reactions 1 assignee Claimed by @kirozeng View on GitHub
enhancement
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 问题

`--text-secondary` 与 `--text-tertiary` 的**强弱关系和命名相反**:叫「三级」的那个比叫「二级」的更清楚。两种模式都有,light / dark 一致。

| | 二级 `text-secondary` | 三级 `text-tertiary` | |
|---|---|---|---|
| Light(页底 `#EDEDED`) | `#8C8E94` → **2.80** | `#686B72` → **4.56** | 倒置 |
| Dark(页底 `#2A2828`) | `#6F6F6F` → **2.92** | `#BFC1C4` → **8.13** | 倒置 |

(数字为对比度,值取自当前 `main` 的 `themes/builtin/cindy-light.ts` / `cindy-dark.ts`。)

## 为什么会这样

一次**选择性无障碍整改**留下的结果,源码注释里有痕迹:

- `text-secondary` — 注释为「直映: 二级信息; **U2 例外**」,当年裁决忠于设计稿原值,列为豁免项,没有整改
- `text-tertiary` — 注释为「**整改**: 非 U2 token AA」,因为不在豁免名单,被压深到达标

于是被整改的那个反而变强了,而名字没跟着调整。

## 为什么值得修

1. **命名会误导取色**。`--text-secondary` 有 422 处消费、`--text-tertiary` 有 486 处,且**经常出现在同一界面**(插件设置、模型选择器、能力设置等)。开发者按名字选「更弱的三级」,实际得到的是更强的颜色。
2. **同族命名已经交叉**。`text-secondary-mid` 的值落在三级档(`#686B72`),比 `text-secondary` 还强;`text-tertiary-stone` / `text-tertiary-mid` 则**零消费**,是历史空槽。
3. **dark 的弱化层次严重偏心**:正文 `11.98` → 三级 `9.86` → 二级 `3.53`。三级几乎不算弱化,二级又弱得多;light 侧 `16.05 → 4.94 → 3.29` 的分布明显更均匀。

## 方案对比

### 方案 A:交换值(不推荐)

让 `text-secondary` 变强、`text-tertiary` 变弱。

- 观感影响约 **900 处** UI,需要大范围实机核对
- 要**推翻 U2 豁免裁决**,决策表需重新裁定
- 风险是视觉性的,只能靠眼睛验,无法自动化

### 方案 B:交换名字(推荐)

值原地不动,把两个 token 名互换,让名字与强弱一致。

- **观感零变化**,每个像素都不动
- 不触碰 U2 裁决(值没变)
- 风险是机械性的,可由 typecheck + 单测覆盖

## 方案 B 的四处连带(不处理会断)

1. **同族 token 需一并重排(约 12 个)**
`text-secondary-cross` / `text-secondary-mid` / `text-tertiary-stone` / `text-tertiary-mid` / `text-tertiary-hsl` / `text-disabled` / `text-disabled-tertiary` / `text-placeholder` / `muted-foreground` 等。
尤其 `text-tertiary-hsl` 是 `text-tertiary` 的 HSL 孪生,只换主名会让**同色两种写法不再一致**(破坏现有不变量)。

2. **移动端同名体系**
`apps/mobile/src/theme/tokens.ts` 有 `textSecondary` / `textTertiary`,注释明确「与桌面 `text-secondary` 同步」。全仓 342 处命中。
⚠️ 需先确认改动是否进入 **runtime fingerprint**;若触发冷更,按 `docs/dev-rules/mobile-development.md` 走把关人确认。

3. **外部主题导入映射表**
`apps/desktop/src/shared/theme-import/palette.ts` 把外部主题角色映射到这些 token 名,不同步会让导入的主题**装错格子**。

4. **存量本地主题会整体倒过来**(P0 风险)
用户已导出的本地主题 JSON 冻结了 `text-secondary: <浅灰>`,改名后加载会落进新的(本该更深的)`text-secondary`,层次反转。
按 `docs/dev-rules/plugin-security-and-authoring.md` 的存量兼容红线口径,**必须自带加载期迁移**;`themes/local-themes-normalize.ts` 已有同类先例(引入 `--text-placeholder` slot 时的归一化),照该模式补一段 key 对调即可。

## 落地清单

- [ ] 注册表 + 同族 12 个 token 重排(`themes/colors.ts`)
- [ ] 调用点改名 ~900 处 — **必须三步走**:`A→TMP`、`B→A`、`TMP→B`,两轮直接替换会自我覆盖
- [ ] `local-themes-normalize.ts` 补加载期 key 对调迁移 + 单测
- [ ] `theme-import/palette.ts` 映射表同步
- [ ] 单测期望表:`themes/__tests__/cindyDecisionData.ts`
- [ ] 顺手清理零消费空槽:`text-tertiary-stone` / `text-tertiary-mid` / `text-secondary-cross`
- [ ] 移动端 `tokens.ts` 同步(**先查冷更指纹**)
- [ ] 文档:`docs/design-rules/DESIGN.md` + `docs/design-rules/token-decision-table.md`

## 建议的推进方式

拆成两个 PR,避免一次性跨端:

1. **PR1 — 桌面端**:注册表重排 + 调用点改名 + 本地主题迁移 + 单测 + 文档
2. **PR2 — 移动端**:确认冷更影响后同步 `tokens.ts`

另:dark 的弱化层次偏心(正文 11.98 / 三级 9.86 距离过近)是**独立议题**,属于调值而非改名,建议不要和本 issue 混做。

---

背景:本问题在一轮 Cindy 皮肤色彩审计中发现(暗度调整 + 象牙白底 + 冷暖统一)。倒置关系为原版遗留,非该轮引入;该轮仅为满足 3.0 对比度下限把二级从 2.80 抬到 3.29,倒置关系原样保留。

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.