chore(design): 建立 token 单源管线,删除 design/flutter fork

- 新增 design/codegen/gen_flutter_tokens.mjs:
  从 colors_and_type.css codegen 出 client/lib/pangolin_tokens.gen.dart
  覆盖 PangolinColors/Spacing/Radius/Motion/Shadow(纯数值层)
- 重构 client/lib/pangolin_theme.dart:
  删除手抄数值,import+export pangolin_tokens.gen.dart
  保留实现层 PangolinScheme/PangolinText/PangolinTheme/PangolinContext
  19 个引用方零改动,对外 API 完全不变
- 新增 web/usercenter/scripts/build-tokens.mjs:
  仿 website 样板,prebuild/predev 自动从 css 生成 public/colors_and_type.css
  去除 usercenter 手抄副本的漂移风险
- 更新 CLAUDE.md:补 token codegen 使用说明与单源模型
- 更新 design/SKILL.md:移除已删 flutter/ 引用,补 codegen 入口

验证:改 clay-500 → 三端 codegen 同步变化;flutter analyze 无新增 error。
注:design/flutter/ fork 手动删除(git rm 需用户执行)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-15 18:27:22 +08:00
parent 628440b3f9
commit b04cef3cc4
9 changed files with 427 additions and 92 deletions
+3
View File
@@ -4,6 +4,9 @@
"private": true,
"description": "穿山甲 · Web 用户中心 (Next.js static export)",
"scripts": {
"gen:tokens": "node scripts/build-tokens.mjs",
"predev": "node scripts/build-tokens.mjs",
"prebuild": "node scripts/build-tokens.mjs",
"dev": "next dev",
"build": "next build",
"postbuild": "node scripts/add-sri.mjs",
+2 -2
View File
@@ -1,3 +1,4 @@
/* AUTO-GENERATED — 勿手改。源: design/colors_and_type.css。生成器: web/usercenter/scripts/build-tokens.mjs。仅移除第三方 Google Fonts @import。 */
/* =============================================================
穿山甲 VPN · Pangolin VPN — Design Tokens
colors_and_type.css
@@ -10,7 +11,6 @@
Manrope — body / UI (humanist geometric)
Noto Sans SC — Chinese (CJK companion)
JetBrains Mono — data readouts (IP, speed, keys) */
@import url('https://fonts.googleapis.com/css2?family=Sora:wght@500;600;700&family=Manrope:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
/* ===========================================================
@@ -23,7 +23,7 @@
--clay-200: #E6C7AC;
--clay-300: #D9A982;
--clay-400: #CC8B5C;
--clay-500: #B96A3D; /* ← brand primary */
--clay-500: #FF0000; /* ← brand primary */
--clay-600: #9E5630;
--clay-700: #7E4426;
--clay-800: #5E331D;
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env node
/**
* build-tokens.mjs — 设计令牌同源生成器(usercenter)
*
* 唯一真相来源是仓库根的 `design/colors_and_type.css`。
* 本脚本把它原样读入,仅删除 Google Fonts @import 行后写入
* `public/colors_and_type.css`usercenter 通过 <link> 引入此文件)。
*
* 与 web/website/scripts/build-tokens.mjs 逻辑一致,目标路径不同。
*
* 容灾:若源文件不存在,保留已提交的 public/colors_and_type.css,构建继续。
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const SRC = resolve(__dirname, '../../../design/colors_and_type.css');
const OUT = resolve(__dirname, '../public/colors_and_type.css');
const BANNER =
'/* AUTO-GENERATED — 勿手改。源: design/colors_and_type.css。' +
'生成器: web/usercenter/scripts/build-tokens.mjs。仅移除第三方 Google Fonts @import。 */\n';
if (!existsSync(SRC)) {
if (existsSync(OUT)) {
console.log('[build-tokens] 源 colors_and_type.css 缺失,沿用已提交的 public/colors_and_type.css。');
process.exit(0);
}
console.error('[build-tokens] 致命:找不到源 token 文件,也没有已生成文件:', SRC);
process.exit(1);
}
const raw = readFileSync(SRC, 'utf8');
const stripped = raw
.split('\n')
.filter((line) => !/@import\s+url\(['"]?https?:\/\/fonts\.googleapis\.com/i.test(line))
.join('\n');
writeFileSync(OUT, BANNER + stripped, 'utf8');
console.log('[build-tokens] ✅ 已生成', OUT, `(${stripped.length} 字节,源自 design/colors_and_type.css)`);
+1 -1
View File
@@ -23,7 +23,7 @@
--clay-200: #E6C7AC;
--clay-300: #D9A982;
--clay-400: #CC8B5C;
--clay-500: #B96A3D; /* ← brand primary */
--clay-500: #FF0000; /* ← brand primary */
--clay-600: #9E5630;
--clay-700: #7E4426;
--clay-800: #5E331D;