chore: 收口复查遗留项并补 radiogroup 键盘导航

This commit is contained in:
2026-08-08 18:46:43 +08:00
parent 45451c0d49
commit 5cbce86e03
6 changed files with 53 additions and 4 deletions
+9
View File
@@ -0,0 +1,9 @@
# scripts/legacy
保留的旧版分析工具,来自早期手工 CSS 工作流,当前纯 Dark Reader 架构下不再参与日常流程。
- `aggregate.py` — 聚合多路由扫描结果
- `fetch_bundle.py` — 抓取线上部署 CSS bundle
- `probe_conflict.py` — 探测 CSS 覆盖冲突
如需恢复手工 CSS 扫描工作流,可参考这些脚本;否则可在一段时间后删除。
+30
View File
@@ -0,0 +1,30 @@
# 聚合扫描结果:按 (元素, 类名, 问题) 分组,统计影响页面数
import json
import pathlib
from collections import defaultdict
data = json.loads(
(pathlib.Path(__file__).parent / "scan-results.json").read_text(encoding="utf-8")
)
groups = defaultdict(lambda: {"pages": [], "sample": None})
for route, items in data.items():
if route.startswith("__") or isinstance(items, dict):
continue
for it in items:
key = (it["tag"], it["cls"], tuple(it["issues"]))
groups[key]["pages"].append(route)
if groups[key]["sample"] is None:
groups[key]["sample"] = it
# 按影响页面数降序
ranked = sorted(groups.items(), key=lambda kv: -len(kv[1]["pages"]))
for (tag, cls, issues), g in ranked:
s = g["sample"]
pages = g["pages"]
print(f"[{len(pages)}页] <{tag}> .{cls[:80]}")
print(f" 问题: {', '.join(issues)}")
print(f" 路径: {s['path'][:130]}")
print(f" 文本: {s['text'][:40]} 尺寸: {s['size']}")
print(f" 页面: {', '.join(pages[:12])}{' ...' if len(pages) > 12 else ''}")
print()
+54
View File
@@ -0,0 +1,54 @@
# 抓取服务端实际部署的插件 bundle.css,与本地构建产物对比
import pathlib
import re
import time
from playwright.sync_api import sync_playwright
ROOT = pathlib.Path(__file__).parent
PROFILE = ROOT / "pw-profile"
OUT = ROOT / "deployed-bundle.css"
with sync_playwright() as p:
ctx = p.chromium.launch_persistent_context(
str(PROFILE), channel="msedge", headless=True
)
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.goto("https://blog.liuhangyv.top/console/overview", wait_until="domcontentloaded")
time.sleep(4)
text = page.evaluate(
"""async () => {
const sheet = [...document.styleSheets].find(s => s.href && s.href.includes('bundle.css'));
if (!sheet) return null;
return await (await fetch(sheet.href)).text();
}"""
)
ctx.close()
if not text:
print("未找到 bundle.css")
raise SystemExit(1)
OUT.write_text(text, encoding="utf-8")
local = (ROOT.parent / "ui" / "build" / "dist" / "style.css").read_text(encoding="utf-8")
def dark_selectors(css: str) -> set:
# 提取所有 [data-halo-theme=dark] 规则的选择器(粗略切分)
return set(re.findall(r"(\[data-halo-theme=dark\][^{]+)\{", css))
dep = dark_selectors(text)
loc = dark_selectors(local)
print(f"部署版 dark 规则选择器数: {len(dep)}")
print(f"本地构建 dark 规则选择器数: {len(loc)}")
print(f"本地有而部署没有(未部署的新覆盖): {len(loc - dep)}")
for s in sorted(loc - dep)[:40]:
print(" +", s[:110])
print(f"部署有而本地没有(本地已删除的旧规则): {len(dep - loc)}")
for s in sorted(dep - loc)[:40]:
print(" -", s[:110])
for kw in ["description-item__label", "description-item__content", "empty-title",
"menu-item-title", "alert-wrapper"]:
print(f"关键字 {kw!r}: 部署版={'' if kw in text else ''} 本地={'' if kw in local else ''}")
+49
View File
@@ -0,0 +1,49 @@
# 冲突溯源:找出与插件暗色规则竞争的原生规则及其样式表加载顺序
import pathlib
import time
from playwright.sync_api import sync_playwright
ROOT = pathlib.Path(__file__).parent
PROFILE = ROOT / "pw-profile"
with sync_playwright() as p:
ctx = p.chromium.launch_persistent_context(
str(PROFILE), channel="msedge", headless=True
)
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.goto("https://blog.liuhangyv.top/console/overview", wait_until="domcontentloaded")
try:
page.wait_for_load_state("networkidle", timeout=10000)
except Exception:
pass
time.sleep(3)
result = page.evaluate(
"""() => {
const targets = ['description-item__label', 'menu-item-title', 'empty-title', 'alert-wrapper'];
const out = [];
const sheets = [...document.styleSheets];
sheets.forEach((sheet, si) => {
let rules;
try { rules = sheet.cssRules; } catch (e) { return; }
for (const r of rules) {
const sel = r.selectorText || '';
if (sel.includes('data-halo-theme')) continue;
for (const t of targets) {
if (sel.includes(t)) {
out.push({ sheetIndex: si, href: (sheet.href || '(inline)').slice(-60), selector: sel.slice(0, 120), body: r.style.cssText.slice(0, 120) });
}
}
}
});
// 插件 bundle.css 的位置
const pluginIdx = sheets.findIndex(s => s.href && s.href.includes('bundle.css'));
return { pluginIdx, totalSheets: sheets.length, matches: out };
}"""
)
ctx.close()
print(f"插件 bundle.css 样式表序号: {result['pluginIdx']} / 共 {result['totalSheets']}")
for m in result["matches"]:
print(f"[sheet #{m['sheetIndex']:>2}] {m['selector']}")
print(f" {m['body']} <- {m['href']}")