Files
XplorePlane/tools/Check-NovaColorTokens.ps1
zhengxuan.zhang 59c1707393 refactor(ui): InspectionTaskWizardWindow 全量令牌化(107 处)
检测任务向导 9 阶段模板中全部裸 HEX 颜色和越界字号替换为 Nova 令牌引用,
残留归零。这是 P3 逐页迁移的第一个文件,也是单文件改动量最大的一个。

颜色映射
- #FFFFFF(根背景/容器白底)→ NovaSurfaceContainerBrush
- #F5F6F7(左侧步骤轨)/ #FAFAFA(卡片浅背景)→ NovaSurfaceContainerLowBrush
- #E0E0E0(分隔线/边框/待定态灰)→ NovaOutlineVariantBrush
- #1B1B1B(主要文字)→ NovaOnSurfaceBrush
- #5A5A5A(次要文字)→ NovaOnSurfaceVariantBrush
- #FFFFFF(白色前景)→ NovaOnPrimaryBrush
- #107C10(完成态/运行态绿)→ NovaSuccessBrush
- #D13438(失败红)→ NovaErrorBrush
- #B0B0B0(禁用态按钮)→ NovaOnBackgroundDisabledBrush
- #F0F5FF/#B0C4DE/#1B5E9A/#3A6A9A/#7A9ABA(信息提示卡片组)→
  NovaInfoContainerBrush / NovaInfoBrush / NovaPrimaryBrush / NovaOnSurfaceVariantBrush

字号收敛
- FontSize="13" → NovaFontSizeBody (14):全部替换
- FontSize="14" → NovaFontSizeBody (14):统一引用令牌
- FontSize="16" → NovaFontSizeBodyStrong (16):标题
- FontSize="12" → NovaFontSizeCaption (12):说明文字
- FontSize="20" → NovaFontSizeSubtitle (18):判定结果大标题
- FontSize="11" → 保留现状(步骤数字,密集面板例外)
2026-07-31 17:29:58 +08:00

163 lines
6.7 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
NOVA UI 规范护栏:禁止新增裸 HEX 颜色值。
.DESCRIPTION
对应 .kiro/steering/ui-design.md 第 6 节「编码约束 · 禁止裸 HEX」。
颜色必须统一走 Themes/NovaColors.xaml 中的令牌(NovaXxxBrush /
NovaXxxColor),不允许在页面或代码里直接写十六进制色值。
仓库里历史遗留的裸 HEX 还有大量未迁移(P3 阶段尚在推进,详见
ui-design.md 第 7 节迁移顺序),因此本护栏默认是【增量模式】:
只检查相对于某个基准(默认与 origin 的合并基点)新增或修改的行,
不会因为历史存量而挡住无关的提交。要看全量现状用 -Mode Full。
范围限定为 XplorePlane 主项目(原生 WPF 面 + 代码侧),与
ui-design.md 第 4 节记录的范围边界一致:
- 排除 Themes/Nova*.xaml 本身(它是唯一允许出现裸 HEX 的地方)
- 排除 obj/bin 生成目录
- 不扫描跨模块项目(XP.Common、XP.Hardware.* 等)——那些明确
标注为「本次不做」,不应被这道护栏误挡
正则只匹配带引号的属性值形式 ="#RRGGBB(AA)",不匹配裸文本,
因此不会对「说明性注释里提到某个十六进制色值」产生误报
(例如 "原 #E3F0FF 浅蓝强调底,语义对应 NOVA secondaryContainer"
这类迁移记录注释)。
.PARAMETER Mode
Diff(默认):只检查增量(git diff 新增行)。
Full:扫描全部现存文件,用于生成现状报告,不建议作为提交门禁。
.PARAMETER Base
Diff 模式下的比较基准。默认自动探测 origin/主分支的合并基点;
在本地无网络/无远程的场景可显式传入一个 commit/分支名。
.PARAMETER Path
要扫描的项目根目录。默认是仓库中的 XplorePlane 主项目目录。
.EXAMPLE
pwsh tools/Check-NovaColorTokens.ps1
提交前跑:只检查本次改动是否新增了裸 HEX。
.EXAMPLE
pwsh tools/Check-NovaColorTokens.ps1 -Mode Full
生成全量现状报告(预期会有大量历史命中,仅供参考)。
.NOTES
退出码:0 = 未发现违规;1 = 发现违规。
没有现成 CI 配置时,建议接成 pre-commit(或 Kiro PreToolUse)钩子,
命令示例:
pwsh -NoProfile -File tools/Check-NovaColorTokens.ps1
一旦引入正式 CI 流水线,直接调用本脚本(Diff 模式)作为一个步骤即可。
#>
param(
[ValidateSet('Diff', 'Full')]
[string]$Mode = 'Diff',
[string]$Base,
[string]$Path = (Join-Path $PSScriptRoot '..\XplorePlane')
)
$ErrorActionPreference = 'Stop'
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$Path = (Resolve-Path $Path).Path
# 带引号的属性值形式:Background="#FFFFFF"、Value="#1A2B3C"、
# "#2E7D32"C# 字符串字面量)等。不匹配裸文本,避免命中注释里的说明文字。
$hexPattern = '="#[0-9A-Fa-f]{6,8}"'
function Test-IsExcluded {
param([string]$RelativePath)
if ($RelativePath -match '[\\/](obj|bin)[\\/]') { return $true }
if ($RelativePath -match '[\\/]Themes[\\/]Nova.*\.xaml$') { return $true }
return $false
}
$violations = @()
if ($Mode -eq 'Full') {
$files = Get-ChildItem -Recurse -Path $Path -Include *.xaml, *.cs -File |
Where-Object { -not (Test-IsExcluded $_.FullName.Substring($RepoRoot.Length + 1)) }
foreach ($file in $files) {
$matches = Select-String -Path $file.FullName -Pattern $hexPattern -AllMatches
foreach ($m in $matches) {
foreach ($hit in $m.Matches) {
$violations += [pscustomobject]@{
File = $file.FullName.Substring($Path.Length + 1)
Line = $m.LineNumber
Snippet = $m.Line.Trim()
Hex = $hit.Value
}
}
}
}
}
else {
# Diff 模式:只看 git diff 里新增的行(+ 开头,排除 +++ 文件头),
# 且限定在 XplorePlane 目录下的 .xaml/.cs 文件。
if (-not $Base) {
$Base = git -C $RepoRoot merge-base HEAD origin/HEAD 2>$null
if (-not $Base) { $Base = git -C $RepoRoot rev-parse HEAD~1 2>$null }
if (-not $Base) { $Base = 'HEAD' }
}
# 同时覆盖已提交的改动(Base..HEAD)与尚未提交的工作区改动,
# 这样在提交前本地跑一次就能拦住,不必依赖已经 commit。
$diffArgs = @('-C', $RepoRoot, 'diff', '--unified=0', "$Base", '--', 'XplorePlane/*.xaml', 'XplorePlane/*.cs')
$committedDiff = & git @diffArgs 2>$null
$workingDiff = & git -C $RepoRoot diff --unified=0 -- 'XplorePlane/*.xaml' 'XplorePlane/*.cs' 2>$null
$stagedDiff = & git -C $RepoRoot diff --unified=0 --cached -- 'XplorePlane/*.xaml' 'XplorePlane/*.cs' 2>$null
$currentFile = $null
$currentLine = 0
foreach ($line in ($committedDiff + $workingDiff + $stagedDiff)) {
if ($line -match '^\+\+\+ b/(.+)$') {
$currentFile = $matches[1]
continue
}
if ($line -match '^@@ -\d+(?:,\d+)? \+(\d+)') {
$currentLine = [int]$matches[1]
continue
}
if ($line -match '^\+(?!\+\+)(.*)$') {
$content = $matches[1]
if ($currentFile -and -not (Test-IsExcluded $currentFile)) {
if ($content -match $hexPattern) {
foreach ($hit in [regex]::Matches($content, $hexPattern)) {
$violations += [pscustomobject]@{
File = $currentFile
Line = $currentLine
Snippet = $content.Trim()
Hex = $hit.Value
}
}
}
}
$currentLine++
continue
}
if ($line -match '^-') { continue }
}
}
# 同一行可能被 committedDiff/workingDiff/stagedDiff 重复统计,按 文件+行+片段 去重。
$violations = $violations | Sort-Object File, Line, Snippet -Unique
if ($violations.Count -eq 0) {
$scope = if ($Mode -eq 'Full') { '全量扫描' } else { "增量扫描(基准 $Base" }
Write-Host "[NOVA] 未发现新增裸 HEX 颜色值($scope)。" -ForegroundColor Green
exit 0
}
Write-Host "[NOVA] 发现 $($violations.Count) 处裸 HEX 颜色值,须改为引用 Themes/NovaColors.xaml 中的令牌:" -ForegroundColor Red
Write-Host ""
foreach ($v in $violations) {
Write-Host (" {0}:{1}" -f $v.File, $v.Line) -ForegroundColor Yellow
Write-Host (" {0}" -f $v.Snippet)
}
Write-Host ""
Write-Host "参见 .kiro/steering/ui-design.md 第 6 节「禁止裸 HEX」。" -ForegroundColor DarkYellow
exit 1