令牌驱动方案(主目标:与 dsh-web-ui 皮肤中心兼容): - 面板表面改用通用卡片令牌 --dsw-alias-bg-layer-1,不再消费宿主左导航专属 --dsw-specific-sidebar-fill——dsh-web-ui 10 款皮肤全部覆盖 --dsw-alias-* 层,换肤后侧边栏自动跟随,零每皮肤适配(#60/#105/#106)。 - effectiveTokenValue 增加 alpha 阈值(新增 colorAlpha 解析 computed 颜色): transparent 与 alpha<0.9 的半透明玻璃值(dsh-web-ui 皮肤 bg-base 为 rgba 0.16–0.7)一律回退不透明底色,终端/编辑器文字永不叠在皮肤背景画上 (#90);≥0.9 的近不透明值放行,皮肤仍可控终端表面。 独立修复(保留): - z-index 降到 DSH 浮层栈(100+)之下:面板 40 / 按钮簇 45 / 角手柄面板内 局部 2,Cordis 弹出框不再被底部工作台遮挡(#52)。 - 角手柄移入右面板、CSS 相对定位(bottom: calc(var(--dsh-sidebar-height) + 6px)),删除 JS 内联 viewport 坐标。 - 刷新按钮统一 14px(#57 前半)。 - 拖拽逐帧回归 e2e(#92):真实挂载下 rAF 采样(拖条以 cursor: col-resize 语义定位),断言拖拽期间 data-dsh-sidebar-dragging 存在、#root transition 为 none、会话列与面板边单调 1:1 跟随(实测通过)。 按 KISS 回退首版契约:类名 kebab-case 改名与 data-bs-* 语义钩子全部移除 (令牌驱动下不需要,改名引入无谓 breaking),skin-hooks 测试删除; mount e2e 改为断言 --dsh-sidebar-width 布局变量随面板挂载生效。 文档:AGENTS.md §8 重写为「皮肤兼容(令牌驱动)」;设计文档记录决策与 回退。README 与版本号不在本批更新(发布流程统一处理)。 测试:tests/theme.spec.ts(colorAlpha + effectiveTokenValue 阈值); typecheck/vitest(511)/build/consumer-types/test:mount 全绿。
This commit is contained in:
@@ -30,6 +30,72 @@ export function tokenValue(name: string): string {
|
||||
return getComputedStyle(document.body).getPropertyValue(name).trim()
|
||||
}
|
||||
|
||||
/** Minimal alpha for a token color to count as effectively opaque. Skin
|
||||
* systems turn `--dsw-alias-bg-base` translucent for glass panels (the
|
||||
* dsh-web-ui skins use rgba 0.16–0.7; `transparent` is 0); below this
|
||||
* floor a text surface (terminal, editor) would render over the skin's
|
||||
* backdrop art, so callers fall back to an opaque color. Values at or
|
||||
* above the floor (e.g. a skin's scoped 0.96 porcelain) pass through —
|
||||
* the skin still controls the surface. */
|
||||
const OPAQUE_ALPHA_MIN = 0.9
|
||||
|
||||
/** The alpha channel of a computed CSS color, or null when the format is
|
||||
* not parseable (named colors, `color()`… — treated as opaque). Handles
|
||||
* the shapes getComputedStyle actually returns: the rgb()/rgba() and
|
||||
* hsl()/hsla() function forms (comma or space syntax, with or without the
|
||||
* `/ alpha` slot) and the #rgb/#rgba/#rrggbb/#rrggbbaa hex family. */
|
||||
export function colorAlpha(color: string): number | null {
|
||||
const s = color.trim()
|
||||
// #rgb / #rgba / #rrggbb / #rrggbbaa
|
||||
const hex = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(s)
|
||||
if (hex !== null) {
|
||||
const digits = hex[1]!
|
||||
if (digits.length === 3 || digits.length === 4) {
|
||||
const a = digits.length === 4 ? digits[3]! : 'f'
|
||||
return parseInt(a + a, 16) / 255
|
||||
}
|
||||
const alphaHex = digits.length === 8 ? digits.slice(6) : 'ff'
|
||||
return parseInt(alphaHex, 16) / 255
|
||||
}
|
||||
// rgb(r g b) / rgb(r g b / a) / rgba(r, g, b, a) — the trailing slot is alpha.
|
||||
const fn = /^(rgba?|hsla?)\(([^)]+)\)$/i.exec(s)
|
||||
if (fn !== null) {
|
||||
const parts = fn[2]!.split(/[,\s/]+/).filter(Boolean)
|
||||
const alphaPart = parts[3]
|
||||
if (alphaPart === undefined) return 1
|
||||
const alpha = Number.parseFloat(alphaPart)
|
||||
return Number.isFinite(alpha) ? alpha : 1
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* A token value that actually PAINTS something — the guard for text
|
||||
* surfaces (issue #90). Skin systems routinely set global tokens to
|
||||
* `transparent` (glass skins) or translucent glass values (`rgba(…,0.16–0.7)`,
|
||||
* e.g. the dsh-web-ui skins) — both are truthy strings, so callers using
|
||||
* `|| fallback` never fire and the terminal/editor goes see-through over
|
||||
* the skin's backdrop. This returns '' for visually inert values (unset
|
||||
* keywords, transparent, and any color below the opacity floor) so the
|
||||
* caller's fallback chain engages; effectively opaque values pass through.
|
||||
*/
|
||||
export function effectiveTokenValue(name: string): string {
|
||||
const raw = tokenValue(name)
|
||||
switch (raw) {
|
||||
case '':
|
||||
case 'transparent':
|
||||
case 'initial':
|
||||
case 'inherit':
|
||||
case 'unset':
|
||||
return ''
|
||||
default: {
|
||||
const alpha = colorAlpha(raw)
|
||||
if (alpha !== null && alpha < OPAQUE_ALPHA_MIN) return ''
|
||||
return raw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to color-scheme flips (the presenter toggles the body
|
||||
* attribute). The callback fires after the attribute changed; re-read the
|
||||
|
||||
Reference in New Issue
Block a user