/* ===================================================================== * SGLV PTW 游戏数据浮窗层(框架 + 7 Tab 合并)—— 样式层已改造为 token 消费者 * --------------------------------------------------------------------- * v2.0.6 样式改造(由 migrate-ptw-css.js 生成,逻辑代码零改动): * · 36 处未定义的 --sglv-text-dim → --sglv-text-secondary * · 7 处未定义的 --sglv-panel(-2) → --sglv-bg / --sglv-surface-deep * · 200+ 处硬编码色值 → 全局语义 token * · 8 档 rgba(102,192,244,*) → accent-wash / soft / strong 三档 * · 3 种橙 (#e8a33d/#f59e0b/#ff9800) → --sglv-amber / --sglv-orange * · 5 份 injectCSS 样板 → SGLVTheme.ensureStyle * 新增能力(来自 sglv-libs-theme.lib.js):主题切换 / 焦点环 / 统一滚动条 / * 等宽数字 / prefers-reduced-motion。 * ⚠️ 依赖顺序:core → sglv-libs-theme → ptw(本库) * ===================================================================== */ /* ===================================================================== * SGLV PTW 游戏数据浮窗层(框架 + 8 Tab 合并) * 由 script_libs 下 8 个单库文件按原 @require 顺序合并而来。 * 各库均为自包含 IIFE,按序拼接即等价于逐个 @require 加载。 * 单库源码已删除;如需拆回,按各分段头注释切分即可。 * ===================================================================== */ /* ==== SGLV-THEME-INLINE-BEGIN (inline-theme-into-ptw.js 自动生成,勿手改) ==== */ /** * Token 层内联块 —— 内容逐字来自 libs/sglv-libs-theme.lib.js(v2.0.2), * 由 docs/inline-theme-into-ptw.js 生成,**勿手改**:要改 token / 基座样式请改 theme 库后重跑脚本。 * 为什么内联:token 是 PTW 布局样式的唯一依赖,若 PTW 库单独上线而 token 层缺席, * 浮窗会整体塌陷(曾发生的线上故障)。内联后 PTW 自带 token, * 与远程 @require 是否包含独立 theme 库无关。 */ /* ===================================================================== * SGLV Theme / Token Layer v2.0.2 * --------------------------------------------------------------------- * 定位:全局唯一样式源(Single Source of Truth)。 * * 为什么需要它(改造背景): * 1) core 的 :root 只定义了 16 个 --sglv-* 变量,而 PTW 引用了 * --sglv-text-dim(36 次) / --sglv-panel(4 次) / --sglv-panel-2(3 次) * 这些变量在 core / 主脚本中**从未定义** → 全部走 fallback, * 导致 PTW 的次要文字(#94a3b8) 与全站(#8a9ba8) 不是同一个灰, * 浮窗底色(#1a2733 不透明) 与主面板(rgba 半透明玻璃) 也不是同一材质。 * 2) core 侧滑栏另有 --sgis-* 一套 token(purple: #1a9fff), * PTW 又是 #66c0f4 —— 同屏两种蓝、三份变量表。 * 3) 全项目无任何主题分支(无 [data-theme] / prefers-color-scheme), * storage.setUiTheme() 只切 DOM,不切颜色。 * 4) 各 Tab 各自 createElement('style'),无 ID 去重、无 try 保护, * 主题切换要逐个改。 * * 本库职责: * A. 补齐 / 收敛全部语义 token(含兼容别名,旧写法继续可用) * B. 提供 dark(默认) / purple / light 三套主题,切换只改一个属性 * C. 统一样式注入器 SGLVTheme.ensureStyle(),替代 5 份 injectCSS 样板 * D. 提供 PTW 浮窗基座样式(交互态 / 可访问性 / 响应式), * Tab 库只写业务布局,不再各自造视觉 * * 加载顺序:core → **theme** → ptw → 主脚本 * ============================================================ */ (function (root) { 'use strict'; if (root.SGLVTheme) return; // 幂等:重复 @require 不重复注入 /* ================================================================= * CSS * ============================================================== */ const CSS = ` /* ---------- 1. 语义 Token 基线(dark = 默认,兼容 core 原值) ---------- 注意:这里刻意沿用 core 已有变量的取值,避免改造引发全站视觉回退; 新增的是 core 缺失、且 PTW 实际在用的那一批。 */ :root{ /* —— 色板:文字 —— */ --sglv-text:#c7d5e0; /* 正文(core 原值) */ --sglv-text-secondary:#8a9ba8; /* 次要文字(core 原值) */ --sglv-text-muted:#64748b; /* ★新增:三级文字/轴标签,原 PTW 各自硬编码 */ /* —— 色板:描边 —— */ --sglv-border:rgba(102,192,244,.2); /* 普通分隔线(core 原值) */ --sglv-border-subtle:rgba(102,192,244,.13);/* ★新增:卡片内边线、更弱的分隔 */ --sglv-border-strong:rgba(102,192,244,.32); /* ★新增:选中/强调描边 */ --sglv-surface-border:rgba(148,163,184,.28);/* ★新增:中性描边(非 accent 语义) */ /* —— 色板:表面 —— */ --sglv-surface-1:rgba(255,255,255,.025); /* ★新增:行/条目底 */ --sglv-surface-2:rgba(255,255,255,.055); /* ★新增:卡片底 */ --sglv-surface-3:rgba(255,255,255,.1); /* ★新增:悬浮/按钮底 */ --sglv-surface-deep:#16222e; /* ★新增:设置卡等二级面板底 */ --sglv-surface-elevated:#1c2c3c; /* ★v1.0.2: 抬升表面(浮窗/抽屉),与 base 区分层级 */ --sglv-surface-overlay:rgba(28,44,60,.85);/* ★v1.0.2: 半透明覆盖层(下拉/菜单/Toast) */ /* —— 色板:强调色阶(PTW 原先散落 8 档 rgba(102,192,244,*))—— */ --sglv-accent:#66c0f4; /* 强调主色(core 原值) */ --sglv-accent-wash:rgba(102,192,244,.07);/* hover 极淡底 */ --sglv-accent-soft:rgba(102,192,244,.16); /* 选中态底 / 常规边框 */ --sglv-accent-strong:rgba(102,192,244,.26);/* hover 态底 / 强调边框 */ --sglv-accent-glow:rgba(102,192,244,.35); /* ★v1.0.2: 强调发光(浮窗边/重要提示外光) */ /* —— 色板:语义色 —— */ --sglv-green:#4caf50; /* core 原值 */ --sglv-success:#22c55e; /* ★新增:达成/正向(对齐 PTW 原值) */ --sglv-red:#f44336; /* core 原值 */ --sglv-danger:#ef4444; /* ★新增:危险操作(对齐 PTW 原值) */ --sglv-orange:#ff9800; /* core 原值 */ --sglv-amber:#e8a33d; /* ★新增:警告/连胜(统一 PTW 的 #e8a33d 与 #f59e0b) */ --sglv-amber-wash:rgba(232,163,61,.07); /* ★新增:警示底(极淡) */ --sglv-amber-soft:rgba(232,163,61,.28); /* ★新增:警示描边/分隔 */ --sglv-amber-strong:rgba(232,163,61,.4); /* ★新增:虚线警示边 */ --sglv-danger-wash:rgba(239,68,68,.08); /* ★新增:危险按钮底 */ --sglv-danger-soft:rgba(239,68,68,.16); /* ★新增:危险按钮 hover */ --sglv-danger-strong:rgba(239,68,68,.4); /* ★新增:危险按钮描边 */ --sglv-amber-light:#fbbf24; /* ★新增:稀有档位 */ --sglv-lime:#84cc16; /* ★新增:少见档位 */ --sglv-purple:#a78bfa; /* ★新增:紫色档位 */ --sglv-track:rgba(255,255,255,.07); /* ★新增:进度条轨道 */ /* —— 遮罩 / 代码块 —— */ --sglv-scrim:rgba(0,0,0,.45); /* ★新增:浮窗遮罩 */ --sglv-scrim-strong:rgba(0,0,0,.65); /* ★v1.0.2: 强化遮罩(关键确认) */ --sglv-code-bg:rgba(0,0,0,.3); /* ★新增:诊断栈底 */ /* —— 材质 —— */ --sglv-header-bg:linear-gradient(135deg,#1b2838,#2a475e); /* 与主面板 .sglv-header 完全一致 */ --sglv-shadow-sm:0 2px 8px rgba(0,0,0,.35); /* ★v1.0.2: 微阴影(按钮/小卡片) */ --sglv-shadow:0 8px 32px rgba(0,0,0,.5); /* core 原值 */ --sglv-shadow-md:0 12px 40px rgba(0,0,0,.5); /* ★新增:二级面板阴影 */ --sglv-shadow-lg:0 18px 60px rgba(0,0,0,.55); /* ★新增:浮窗级阴影 */ --sglv-shadow-xl:0 24px 80px rgba(0,0,0,.65);/* ★v1.0.2: 强化阴影(关键操作/确认弹窗) */ /* —— 滚动条 token(收齐 PTW/主面板/侧栏所有自定义滚动条) —— */ --sglv-scrollbar-width:8px; /* ★v1.0.2: 滚动条粗细 */ --sglv-scrollbar-thumb:rgba(102,192,244,.28); /* ★v1.0.2: 滚动条拇指 */ --sglv-scrollbar-thumb-hover:rgba(102,192,244,.45); /* ★v1.0.2: 拇指 hover */ --sglv-scrollbar-track:transparent; /* ★v1.0.2: 滚动条轨道透明 */ /* —— 动效:统一曲线与时长,替代散落的 .15s / .18s / .2s —— */ --sglv-ease:cubic-bezier(.4,0,.2,1); --sglv-dur:150ms; --sglv-dur-fast:100ms; /* ★v1.0.2: 快速过渡(hover) */ --sglv-dur-slow:280ms; /* ★v1.0.2: 慢速过渡(尺寸/弹窗) */ --sglv-transition:all .2s ease; /* core 原值,保留 */ /* —— 刻度:间距(4 的倍数,替代散落的 5/6/7/9/10/12/14)—— */ --sglv-sp-1:4px; --sglv-sp-2:8px; --sglv-sp-3:12px; --sglv-sp-4:16px; --sglv-sp-5:20px; --sglv-sp-6:24px; /* —— 刻度:圆角(收敛散落的 5/6/7/8/9/10/12/16)—— */ --sglv-r-xs:6px; --sglv-r-sm:8px; --sglv-r-md:10px; --sglv-r-lg:12px; --sglv-r-xl:16px; /* —— 刻度:字号 —— */ --sglv-fs-xs:10px; --sglv-fs-sm:11px; --sglv-fs-md:12px; --sglv-fs-base:13px; --sglv-fs-lg:15px; /* —— 动效:统一曲线与时长,替代裸 .15s / .2s —— */ --sglv-ease:cubic-bezier(.4,0,.2,1); --sglv-dur:150ms; --sglv-dur-fast:100ms; /* ★v1.0.2: 快速过渡(hover) */ --sglv-dur-slow:280ms; /* ★v1.0.2: 慢速过渡(尺寸/弹窗) */ --sglv-transition:all .2s ease; /* core 原值,保留 */ /* —— 兼容别名:旧写法零改动继续可用(★关键,防止改造引发回归)—— PTW 全部 36 处 --sglv-text-dim 现在解析到与全站一致的 --sglv-text-secondary */ --sglv-text-dim:var(--sglv-text-secondary); --sglv-panel:var(--sglv-bg); --sglv-panel-2:var(--sglv-surface-deep); } /* ---------- 2. 主题分支 ---------- 切换方式(三选一): document.documentElement.setAttribute('data-sglv-theme','purple') SGLVTheme.setTheme('light') SGLVTheme.setTheme('auto') // 跟随系统 */ [data-sglv-theme="dark"]{color-scheme:dark;} /* purple = 主脚本侧滑栏默认主题的强调色,让浮窗与侧滑栏同屏同蓝 */ [data-sglv-theme="purple"]{ --sglv-accent:#1a9fff; --sglv-border:rgba(26,159,255,.18); --sglv-border-subtle:rgba(26,159,255,.12); --sglv-border-strong:rgba(26,159,255,.3); --sglv-accent-wash:rgba(26,159,255,.06); --sglv-accent-soft:rgba(26,159,255,.15); --sglv-accent-strong:rgba(26,159,255,.24); --sglv-accent-glow:rgba(26,159,255,.33); } [data-sglv-theme="light"]{ color-scheme:light; --sglv-bg:rgba(248,250,252,.98); --sglv-bg-card:rgba(255,255,255,.97); --sglv-text:#1e293b; --sglv-text-secondary:#52647a; --sglv-text-muted:#7c8ba1; --sglv-accent:#0284c7; --sglv-border:rgba(2,132,199,.22); --sglv-border-subtle:rgba(2,132,199,.13); --sglv-border-strong:rgba(2,132,199,.36); --sglv-surface-border:rgba(15,23,42,.16); --sglv-surface-1:rgba(15,23,42,.03); --sglv-surface-2:rgba(15,23,42,.06); --sglv-surface-3:rgba(15,23,42,.1); --sglv-surface-deep:#e8edf3; --sglv-surface-elevated:#ffffff; --sglv-surface-overlay:rgba(255,255,255,.92); --sglv-accent-wash:rgba(2,132,199,.06); --sglv-accent-soft:rgba(2,132,199,.13); --sglv-accent-strong:rgba(2,132,199,.22); --sglv-accent-glow:rgba(2,132,199,.32); --sglv-green:#16a34a; --sglv-success:#16a34a; --sglv-red:#dc2626; --sglv-danger:#dc2626; --sglv-orange:#ea580c; --sglv-amber:#d97706; --sglv-amber-light:#d97706; --sglv-lime:#65a30d; --sglv-purple:#7c3aed; --sglv-amber-wash:rgba(217,119,6,.07); --sglv-amber-soft:rgba(217,119,6,.24); --sglv-amber-strong:rgba(217,119,6,.4); --sglv-danger-wash:rgba(220,38,38,.08); --sglv-danger-soft:rgba(220,38,38,.16); --sglv-danger-strong:rgba(220,38,38,.4); --sglv-track:rgba(15,23,42,.1); --sglv-kpi-bg:rgba(255,255,255,.72); --sglv-section-bg:rgba(241,245,249,.78); --sglv-scrim:rgba(15,23,42,.4); --sglv-scrim-strong:rgba(15,23,42,.6); --sglv-code-bg:rgba(15,23,42,.05); --sglv-header-bg:linear-gradient(135deg,#eef3f9,#dde7f2); --sglv-shadow-sm:0 1px 3px rgba(15,23,42,.08); --sglv-shadow:0 8px 32px rgba(15,23,42,.16); --sglv-shadow-md:0 12px 40px rgba(15,23,42,.18); --sglv-shadow-lg:0 18px 60px rgba(15,23,42,.2); --sglv-shadow-xl:0 24px 80px rgba(15,23,42,.28); --sglv-scrollbar-thumb:rgba(15,23,42,.18); --sglv-scrollbar-thumb-hover:rgba(15,23,42,.32); } /* ---------- 2.5 主题切换平滑过渡 ---------- 只过渡色彩/阴影/背景类属性,避免布局动画(尺寸/位置)引发的卡顿。 关闭开关 .sglv-no-theme-anim 可临时禁用(大量重渲染场景) */ :root{ transition: background-color var(--sglv-dur) var(--sglv-ease), color var(--sglv-dur) var(--sglv-ease), border-color var(--sglv-dur) var(--sglv-ease), box-shadow var(--sglv-dur) var(--sglv-ease); } .sglv-no-theme-anim{transition:none !important;} /* ---------- 3. PTW 浮窗基座(Tab 库只写布局,视觉统一在此)---------- */ /* v2.22.5 关键修复:Steam 页面的 body.v6/#global_header/.newlayout 等高特异性选择器 会用更高优先级覆盖 PTW 的 layout(overlay inset/居中)+ 视觉 win 背景/边框/阴影, 导致浮窗「全塌陷」贴顶左对齐。统一给基座关键属性加 !important 兜底。 借鉴主面板 .sglv-panel{position:fixed!important;...} 的同款抗压策略。 */ /* 3.1 窗口材质:与主面板同一套玻璃质感 */ .sglv-ptw-win{ background:var(--sglv-bg)!important; border:1px solid var(--sglv-border)!important; border-radius:var(--sglv-r-xl)!important; box-shadow:var(--sglv-shadow-lg),inset 0 1px 0 var(--sglv-border-subtle)!important; transition:width var(--sglv-dur) var(--sglv-ease),height var(--sglv-dur) var(--sglv-ease); } /* 3.2 头部:复用主面板 .sglv-header 的渐变(此前 PTW 头部是纯色,割裂感明显) */ .sglv-ptw-head{ background:var(--sglv-header-bg)!important; padding:var(--sglv-sp-3) var(--sglv-sp-4)!important; position:relative!important; } .sglv-ptw-head::after{ content:'';position:absolute;left:0;right:0;bottom:-1px;height:1px; background:linear-gradient(90deg,transparent,var(--sglv-border),transparent); opacity:.6; } /* 3.3 Tab:激活态由「整块底色」升级为「淡底 + 底部指示线」, 与主面板 .sglv-tab.active 的色值完全一致 */ .sglv-ptw-tab{ position:relative!important; /* v1.0.3防挤压叠字:Tab 栏是 flex + overflow-x:auto,按钮默认可收缩(min-width:auto 只挡 min-content,flex-shrink 仍会把 6 个 Tab 压进几十 px,文字互相叠印。 桌面端同样必须 flex-shrink:0 —— 原先只在 ≤820px 媒体查询里声明,属漏网。 */ flex:0 0 auto!important; border-radius:var(--sglv-r-xs) var(--sglv-r-xs) 0 0!important; transition:background var(--sglv-dur-fast) var(--sglv-ease),color var(--sglv-dur-fast) var(--sglv-ease); } /* Tab 标签永不折行/永不压缩(叠字的最后一道保险) */ .sglv-ptw-tab>span{white-space:nowrap;} .sglv-ptw-tab:hover{background:var(--sglv-accent-wash);color:var(--sglv-text);} .sglv-ptw-tab.active{background:var(--sglv-accent-soft)!important;color:var(--sglv-accent)!important;font-weight:600!important;} .sglv-ptw-tab.active::after{ content:'';position:absolute;left:10px;right:10px;bottom:-1px;height:2px; background:var(--sglv-accent);border-radius:2px; box-shadow:0 0 8px var(--sglv-accent-glow); } /* 3.4 交互态统一:焦点环 / 悬浮反馈 v1.0.3 选择器修复:原写作后代选择器 ".sglv-ptw :where(...)" / ".sglv-ptw *", 但 DOM 上并不存在 class="sglv-ptw" 的祖先(窗口是 .sglv-ptw-win), 导致焦点环 / 等宽数字 / 动效降级三组规则全部空转。锚点改为 .sglv-ptw-win。 */ .sglv-ptw-win :where(button,[role="tab"],a,input,select):focus-visible{ outline:2px solid var(--sglv-accent)!important; outline-offset:2px!important; border-radius:var(--sglv-r-xs)!important; box-shadow:0 0 0 4px var(--sglv-accent-wash)!important; } .sglv-ptw-win .sglv-ptw-btn:hover{background:var(--sglv-surface-3);color:var(--sglv-text);} .sglv-ptw-win .sglv-ptw-btn:active{transform:translateY(1px);} /* 3.5 滚动条:接入全局滚动条变量(此前 PTW 未纳入 core 的滚动条统一规则) */ .sglv-ptw-body, .sglv-ptw-tabs, .sglv-ptw-pane :where(.sglv-pt-all-list,[class$="-list"],[class$="-tl-list"]){ scrollbar-width:thin; scrollbar-color:var(--sglv-scrollbar-thumb) var(--sglv-scrollbar-track); } .sglv-ptw-body::-webkit-scrollbar, .sglv-ptw-tabs::-webkit-scrollbar, .sglv-ptw-pane :where(.sglv-pt-all-list,[class$="-list"],[class$="-tl-list"])::webkit-scrollbar{ width:var(--sglv-scrollbar-width);height:var(--sglv-scrollbar-width); } .sglv-ptw-body::-webkit-scrollbar-thumb, .sglv-ptw-tabs::-webkit-scrollbar-thumb, .sglv-ptw-pane :where(.sglv-pt-all-list,[class$="-list"],[class$="-tl-list"])::webkit-scrollbar-thumb{ background:var(--sglv-scrollbar-thumb);border-radius:4px; transition:background var(--sglv-dur-fast) var(--sglv-ease); } .sglv-ptw-body::-webkit-scrollbar-thumb:hover, .sglv-ptw-tabs::-webkit-scrollbar-thumb:hover, .sglv-ptw-pane :where(.sglv-pt-all-list,[class$="-list"],[class$="-tl-list"])::webkit-scrollbar-thumb:hover{ background:var(--sglv-scrollbar-thumb-hover); } .sglv-ptw-body::-webkit-scrollbar-track, .sglv-ptw-tabs::-webkit-scrollbar-track, .sglv-ptw-pane :where(.sglv-pt-all-list,[class$="-list"],[class$="-tl-list"])::webkit-scrollbar-track{ background:var(--sglv-scrollbar-track); } /* 3.6 数字对齐:所有数值/时长/金额使用等宽数位,列不再跳动(同 3.4,锚点 .sglv-ptw-win) */ .sglv-ptw-win :where(b,strong,.sglv-ptw-value-score-num,.sglv-ptw-ach-tl-row b, [class*="-val"],[class*="-num"],[class*="-stat-val"],[class*="-count"],[class*="-pct"]){ font-variant-numeric:tabular-nums; } /* 3.7 动效降级:尊重系统「减少动态效果」 */ @media (prefers-reduced-motion:reduce){ .sglv-ptw-win,.sglv-ptw-win *{ transition-duration:.01ms !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; } } /* 3.8 打印 / 强制高对比下的降级 */ @media (forced-colors:active){ .sglv-ptw-tab.active{border:1px solid Highlight;} } `; /* ================================================================= * Token JS 镜像 * —— 供 SVG 图表等「无法直接用 var() 的场景」读取实际取值。 * 注意:SVG 的 fill="var(--x)" 属性形式不生效,必须 JS 读取, * 故 charts 建议改用 readToken(),且要在渲染时调用(主题切换后才生效)。 * ============================================================== */ const colors = { text: 'var(--sglv-text)', textSecondary: 'var(--sglv-text-secondary)', textMuted: 'var(--sglv-text-muted)', accent: 'var(--sglv-accent)', border: 'var(--sglv-border)', borderSubtle: 'var(--sglv-border-subtle)', borderStrong: 'var(--sglv-border-strong)', surface1: 'var(--sglv-surface-1)', surface2: 'var(--sglv-surface-2)', surface3: 'var(--sglv-surface-3)', track: 'var(--sglv-track)', success: 'var(--sglv-success)', danger: 'var(--sglv-danger)', amber: 'var(--sglv-amber)', amberLight: 'var(--sglv-amber-light)', lime: 'var(--sglv-lime)', purple: 'var(--sglv-purple)', }; const THEME_KEY = 'sglv_ui_theme'; /* v1.0.3:基座样式 id。刻意区别于主脚本 applySglvTheme() 使用的 'sglv-theme-style' (那个 id 归"主题覆盖层"所有,内容会被整体替换,两者不可共用)。 */ const BASE_STYLE_ID = 'sglv-theme-base'; /* ================================================================= * API * ============================================================== */ const SGLVTheme = { version: '1.0.0', colors, /** * 注入基座样式(幂等) * v1.0.3 id 修复:原用 id="sglv-theme-style",与主脚本 applySglvTheme() 写入的 * 主题覆盖层 style#sglv-theme-style 同 id —— 后者执行 * el.textContent = theme.css() 会把本基座(:root 全量 token + PTW 基座样式) * 整体覆盖掉,导致 --sglv-sp-* / --sglv-r-* / --sglv-surface-* 等集体失效、 * padding / gap / border-radius 回落初始值 → 浮窗整体「样式塌陷」。 * 基座改用独立 id "sglv-theme-base",与覆盖层彻底解耦(两段 CSS 可共存)。 */ ensureBase() { try { if (!document.getElementById(BASE_STYLE_ID)) { const st = document.createElement('style'); st.id = BASE_STYLE_ID; st.textContent = CSS; (document.head || document.documentElement).appendChild(st); } } catch (e) { /* 样式失败不阻断功能 */ } }, /** * 统一样式注入器 —— 替代各库各自复制的 injectCSS()。 * 同 id 只注入一次,天然幂等;重复 open() / 重复 mount 不会产生重复样式表。 * @param {string} id