|
|
@@ -0,0 +1,75 @@
|
|
|
+#!/usr/bin/env node
|
|
|
+/**
|
|
|
+ * D38: 第九轮——跨页重复色(≥3 处)提升为 uni.scss 全局令牌
|
|
|
+ *
|
|
|
+ * 依据 AGENTS.md / uni.scss §14 约定:同一色值在 ≥2~4 个文件出现即提升全局,
|
|
|
+ * 单页专有色阶仍留在页面级 `$c-*`。本脚本幂等:已存在的令牌/规则不会重复写入。
|
|
|
+ *
|
|
|
+ * 用法: node scripts/d38-round9-tokens.js [--dry]
|
|
|
+ */
|
|
|
+const fs = require('fs');
|
|
|
+
|
|
|
+const TOKENS = [
|
|
|
+ ['$facade-fill-slate-25', '#F2F4F7', '冷调极浅底(教师端表单/计划卡)'],
|
|
|
+ ['$facade-fill-slate-50-2', '#F7F9FC', '冷调浅底(与既有 $facade-fill-slate-50 #F8FAFC 区分)'],
|
|
|
+ ['$facade-text-slate-600', '#5A6478', '深岩灰正文(教师端计划/AI 提示)'],
|
|
|
+ ['$facade-text-gray-600', '#4B5563', '中性灰正文(活动详情/通用说明)'],
|
|
|
+ ['$facade-ink-navy', '#1A2A4A', '藏青标题(门禁/深色卡片标题)'],
|
|
|
+ ['$status-danger-light-2', '#FCA5A5', '错误浅色(挑战卡/失败态描边)'],
|
|
|
+ ['$status-danger-strong-3', '#E53E3E', '错误深色(问卷/报告异常值)'],
|
|
|
+ ['$status-danger-tint-4', '#FDE8E8', '错误极浅底(驳回/异常标签底)'],
|
|
|
+ ['$status-danger-tint-5', '#FFF0F0', '错误极浅底之二(报告确认提示底)'],
|
|
|
+ ['$status-warning-amber', '#FFC107', '琥珀警示(评分/星级)'],
|
|
|
+ ['$status-warning-4', '#E6A23C', 'Element 警示橙(反馈弹窗)'],
|
|
|
+ ['$status-warning-gold', '#F0B429', '暖金警示(报告列表徽标)'],
|
|
|
+ ['$mat-green-700', '#388E3C', 'Material 绿 700(完成/通过)'],
|
|
|
+ ['$mat-deep-orange', '#FF5722', 'Material 深橙(记录详情强调)'],
|
|
|
+ ['$tint-blue-300', '#93C5FD', '蓝 300 描边/进度(空间测试)'],
|
|
|
+ ['$accent-violet-300', '#C4B5FD', '紫 300 强调(DAN 报告)'],
|
|
|
+ ['$tint-sky-soft-2', '#EAF4FC', '天蓝浅底(健康反馈/我的反馈)'],
|
|
|
+ ['$tint-sky-ghost', '#F0F7FF', '天蓝极浅底(报告上传/列表)'],
|
|
|
+ ['$tint-green-ghost', '#F0F9EB', '绿极浅底(成员列表/成功提示)'],
|
|
|
+ ['$accent-pink-tint-2', '#FCE4EC', '粉浅底(报告详情/情绪标签)'],
|
|
|
+ ['$wechat-green', '#07C160', '微信品牌绿(授权/分享入口)'],
|
|
|
+];
|
|
|
+
|
|
|
+const DRY = process.argv.includes('--dry');
|
|
|
+
|
|
|
+// ---- 1) uni.scss ----
|
|
|
+const SCSS = 'uni.scss';
|
|
|
+let scss = fs.readFileSync(SCSS, 'utf8');
|
|
|
+const eolS = scss.includes('\r\n') ? '\r\n' : '\n';
|
|
|
+const missing = TOKENS.filter(([name]) => !new RegExp('^\\s*\\' + name + '\\s*:', 'm').test(scss));
|
|
|
+if (missing.length) {
|
|
|
+ const block = eolS +
|
|
|
+ '// ==================== §15 第九轮 · 跨页重复色提升(2026-10-21) ====================' + eolS +
|
|
|
+ '// 判据:同一色值在 ≥3 个页面/组件出现,且不属于页面专有色阶;单页色阶仍用 $c-* 留在页面内。' + eolS +
|
|
|
+ missing.map(([name, hex, desc]) => `${name}: ${hex};`.padEnd(40) + `// ${desc}`).join(eolS) + eolS;
|
|
|
+ scss += block;
|
|
|
+ if (!DRY) fs.writeFileSync(SCSS, scss, 'utf8');
|
|
|
+ console.log('uni.scss 新增令牌:', missing.length);
|
|
|
+} else {
|
|
|
+ console.log('uni.scss 令牌已齐备,跳过');
|
|
|
+}
|
|
|
+
|
|
|
+// ---- 2) replace-hex-to-token.js(脚本文件统一 LF,避免整文件行尾翻新) ----
|
|
|
+const RULES = 'scripts/replace-hex-to-token.js';
|
|
|
+let rules = fs.readFileSync(RULES, 'utf8').replace(/\r\n/g, '\n');
|
|
|
+const eolR = '\n';
|
|
|
+const newRules = [];
|
|
|
+for (const [name, hex] of TOKENS) {
|
|
|
+ if (rules.toUpperCase().includes("'" + hex.toUpperCase() + "'")) continue;
|
|
|
+ newRules.push(` ['${hex.toUpperCase()}', '${name}'],`);
|
|
|
+ newRules.push(` ['${hex.toLowerCase()}', '${name}'],`);
|
|
|
+}
|
|
|
+if (newRules.length) {
|
|
|
+ const marker = '\n].sort((a, b) => b[0].length - a[0].length)';
|
|
|
+ const at = rules.indexOf(marker);
|
|
|
+ if (at === -1) { console.log('FAIL: 规则数组锚点未找到'); process.exit(1); }
|
|
|
+ const block = eolR + ' // ---- 第九轮(跨页重复色提升,2026-10-21)----' + eolR + newRules.join(eolR);
|
|
|
+ rules = rules.slice(0, at) + block + rules.slice(at);
|
|
|
+ if (!DRY) fs.writeFileSync(RULES, rules, 'utf8');
|
|
|
+ console.log('replace-hex-to-token.js 新增规则:', newRules.length);
|
|
|
+} else {
|
|
|
+ console.log('替换规则已齐备,跳过');
|
|
|
+}
|