feat(web): 双档 UI 模式(性能档 = 现状 / Smooth Corner 华丽档)+ 开关挂载(裁决 16.4.4)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- design/uiMode.ts:档位纯逻辑(localStorage `cyrene.ui-mode` 持久化、跨标签页同步、未知值回落默认档),
  只改 <html> 类名与 data 属性 ⇒ 不碰 React 树、不重挂载、几何尺寸不变
- 性能档=**现状**:tokens.css / styles/index.css 的改动**全为新增(0 删除)**,且全部限定在
  `:root.ui-mode-fancy` 下;75 元素签名比对证明性能档渲染与改动前逐元素一致
- 华丽档对齐六大核心:连续曲率 corner-shape / 多层 Surface 环境光 / 弹簧动效 / 深色优先(浅色单列补偿)/
  毛玻璃升级 / Liquid Glass(4 折射 + RGB 色差 + 鼠标跟踪 + 双层动态边框)
- 开关挂载:main.tsx 在 createRoot 之前 initUiMode(零闪烁);TopBar/Nav/AdminTopBar 三处挂载,
  窄屏(<640px)按既有约定收起(实测否则 375px 角色块被压到 27px、面板溢出 73px),移动端由侧栏抽屉覆盖
- 复核:tsc 0 错 + vite build 成功;uiMode 38 项 node 测试 + headless Chrome 真渲染 30 项(真点击/真持久化/
  真指针事件);变异反证(去掉读回 → 持久化往返必红)
This commit is contained in:
AskaEth committed 2026-10-04 13:41:09 +08:00
1 parent c1a98d7c01
commit 8d70f6d331
9 files changed
+961

No files matched your search

+201
View File
@@ -192,3 +192,204 @@ textarea {
transform: translateX(0);
}
}
/* ═══════════════════════════════════════════════════════════════════════════
双档 UI 模式(裁决 16.4.4 / design/07 §0.1)
上面全部 =「UI 性能模式」(默认档,现状 token 近似,未改一行);
本节全部以 `:root.ui-mode-fancy` 限定 ⇒ 性能档下**零生效、零开销**。
档位由 src/design/uiMode.ts 打在 <html> 上(类名 + data-ui-mode)。
切换只改 <html>、不改几何尺寸 ⇒ 不丢会话状态、不明显闪烁。
═══════════════════════════════════════════════════════════════════════════ */
/* —— 1. Smooth Corner:连续曲率(k=0.55 的 squircle 角型,直线到圆弧丝滑过渡)——
只作用于「明确设计过圆角」的元素;`rounded-full` 的真圆(头像/指示点)不受影响。
不支持 corner-shape 的浏览器自动回落 border-radius 近似,无副作用。 */
:root.ui-mode-fancy [class*="rounded"]:not([class*="rounded-full"]),
:root.ui-mode-fancy .glass,
:root.ui-mode-fancy .liquid-glass,
:root.ui-mode-fancy .liquid-glass-soft,
:root.ui-mode-fancy .liquid-glass-accent {
corner-shape: var(--mu-corner-shape);
}
/* —— 2. 多层 Surface:整屏环境光,给所有玻璃表面一层被照亮的底 —— */
:root.ui-mode-fancy body::before {
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image: var(--mu-ambient);
}
/* —— 5. 毛玻璃:顶栏 / 侧栏 / 输入栏加「上缘受光 + 折射内描边」 —— */
:root.ui-mode-fancy .glass {
backdrop-filter: blur(var(--mu-glass-blur)) saturate(var(--mu-glass-saturate));
-webkit-backdrop-filter: blur(var(--mu-glass-blur)) saturate(var(--mu-glass-saturate));
box-shadow:
inset 0 1px 0 var(--mu-edge-light),
inset 0 0 0 1px var(--mu-liquid-rim);
}
/* —— 6. Liquid Glass(大件:卡片 / 弹层 / 下拉)——
真折射(默认 4 模式里的预设 1)+ 鼠标跟踪镜面高光 + RGB 色差分离 + 双层动态边框。
第二条 backdrop-filter 带 SVG 位移滤镜:不支持的浏览器在解析期即丢弃该声明,
自动回落第一条的模糊链,不会把玻璃做成透明片。 */
:root.ui-mode-fancy .liquid-glass {
isolation: isolate;
background:
radial-gradient(140% 120% at var(--mu-lens-x, 30%) var(--mu-lens-y, 0%), var(--mu-liquid-specular), transparent 45%),
radial-gradient(120% 90% at 50% 130%, var(--mu-liquid-caustic), transparent 62%),
linear-gradient(135deg, var(--mu-liquid-highlight), transparent 42%),
color-mix(in srgb, var(--mu-surface-4) 78%, transparent);
box-shadow:
var(--mu-elev-3),
inset 0 0 0 1px var(--mu-liquid-rim),
-1px 0 0 var(--mu-liquid-chroma-r),
1px 0 0 var(--mu-liquid-chroma-b);
backdrop-filter: blur(var(--mu-glass-blur)) saturate(var(--mu-glass-saturate));
-webkit-backdrop-filter: blur(var(--mu-glass-blur)) saturate(var(--mu-glass-saturate));
backdrop-filter: blur(3px) saturate(var(--mu-glass-saturate)) url("#mu-refract-1");
rotate: var(--mu-lens-rotate, 0deg);
scale: var(--mu-lens-scale, 1);
transition:
rotate 0.5s var(--mu-spring-slow),
scale 0.5s var(--mu-spring-slow),
transform 0.4s var(--mu-spring),
box-shadow 0.5s var(--mu-ease),
background 0.4s var(--mu-ease);
}
:root.ui-mode-fancy .liquid-glass:hover {
transform: translateY(-2px);
box-shadow:
var(--mu-elev-3),
0 0 0 1px var(--mu-liquid-ring),
-1px 0 0 var(--mu-liquid-chroma-r),
1px 0 0 var(--mu-liquid-chroma-b);
}
/* 双层动态边框:内环(实线流光)+ 外环(色差光晕),各转各的、方向相反。
角度靠 @property 插值;不支持时自动退化为静态双层边框(仍有形、只是不转)。 */
:root.ui-mode-fancy .liquid-glass::before,
:root.ui-mode-fancy .liquid-glass::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
pointer-events: none;
padding: 1px;
background: conic-gradient(
from var(--mu-ring-angle, 0deg),
transparent 0deg,
var(--mu-liquid-ring) 70deg,
transparent 150deg
);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
animation: mu-ring-spin var(--mu-liquid-ring-dur) linear infinite;
}
:root.ui-mode-fancy .liquid-glass::after {
inset: -3px;
padding: 2px;
opacity: 0.6;
filter: blur(7px);
background: conic-gradient(
from var(--mu-ring-angle, 0deg),
var(--mu-liquid-chroma-r) 0deg,
transparent 90deg,
var(--mu-liquid-chroma-b) 220deg,
transparent 310deg
);
animation-direction: reverse;
}
@keyframes mu-ring-spin {
from {
--mu-ring-angle: 0deg;
}
to {
--mu-ring-angle: 360deg;
}
}
/* —— 6b. Liquid Glass 的 4 折射模式:默认最克制(预设 1),元素可用
`data-refract="2|3|4"` 自选更夸张的折射(预设在 uiMode.ts 里注入) —— */
:root.ui-mode-fancy :is(.liquid-glass, .liquid-glass-soft, .liquid-glass-accent)[data-refract="1"] {
backdrop-filter: blur(3px) saturate(1.7) url("#mu-refract-1");
}
:root.ui-mode-fancy :is(.liquid-glass, .liquid-glass-soft, .liquid-glass-accent)[data-refract="2"] {
backdrop-filter: blur(4px) saturate(1.8) url("#mu-refract-2");
}
:root.ui-mode-fancy :is(.liquid-glass, .liquid-glass-soft, .liquid-glass-accent)[data-refract="3"] {
backdrop-filter: blur(5px) saturate(1.9) url("#mu-refract-3");
}
:root.ui-mode-fancy :is(.liquid-glass, .liquid-glass-soft, .liquid-glass-accent)[data-refract="4"] {
backdrop-filter: blur(6px) saturate(2) url("#mu-refract-4");
}
/* —— 聊天气泡(轻量液态玻璃):镜面高光 + 色差分离 + 鼠标跟踪的弹性形变 —— */
:root.ui-mode-fancy .liquid-glass-soft,
:root.ui-mode-fancy .liquid-glass-accent {
rotate: var(--mu-lens-rotate, 0deg);
scale: var(--mu-lens-scale, 1);
transition:
rotate 0.5s var(--mu-spring-slow),
scale 0.5s var(--mu-spring-slow),
box-shadow 0.5s var(--mu-ease),
background 0.4s var(--mu-ease);
}
:root.ui-mode-fancy .liquid-glass-soft {
background:
radial-gradient(130% 160% at var(--mu-lens-x, 30%) var(--mu-lens-y, 0%), color-mix(in srgb, var(--mu-liquid-specular) 62%, transparent), transparent 42%),
linear-gradient(135deg, var(--mu-liquid-highlight), transparent 45%),
color-mix(in srgb, var(--mu-surface-3) 62%, transparent);
box-shadow:
var(--mu-elev-1),
inset 0 0 0 1px var(--mu-liquid-rim),
-0.5px 0 0 var(--mu-liquid-chroma-r),
0.5px 0 0 var(--mu-liquid-chroma-b);
backdrop-filter: blur(14px) saturate(1.6);
-webkit-backdrop-filter: blur(14px) saturate(1.6);
}
:root.ui-mode-fancy .liquid-glass-accent {
background:
radial-gradient(130% 160% at var(--mu-lens-x, 30%) var(--mu-lens-y, 0%), color-mix(in srgb, var(--mu-liquid-specular) 62%, transparent), transparent 42%),
linear-gradient(135deg, var(--mu-liquid-highlight), transparent 45%),
linear-gradient(
180deg,
color-mix(in srgb, var(--mu-accent) 70%, transparent),
color-mix(in srgb, var(--mu-accent) 64%, transparent)
);
box-shadow:
0 8px 22px color-mix(in srgb, var(--mu-accent) 26%, transparent),
inset 0 0 0 1px var(--mu-liquid-rim),
-0.5px 0 0 var(--mu-liquid-chroma-r),
0.5px 0 0 var(--mu-liquid-chroma-b);
backdrop-filter: blur(14px) saturate(1.6);
-webkit-backdrop-filter: blur(14px) saturate(1.6);
}
/* —— 3. 弹簧动效:华丽档的入场也走弹簧,过冲可见(仍只用于入场/交互,不常态抖动) —— */
:root.ui-mode-fancy .mu-rise-in {
animation-duration: 0.52s;
}
/* 尊重系统「减弱动效」:华丽档保留静态的曲率/玻璃/色差,但停掉旋转与跟踪形变 */
@media (prefers-reduced-motion: reduce) {
:root.ui-mode-fancy .liquid-glass::before,
:root.ui-mode-fancy .liquid-glass::after {
animation: none;
}
:root.ui-mode-fancy .liquid-glass,
:root.ui-mode-fancy .liquid-glass-soft,
:root.ui-mode-fancy .liquid-glass-accent {
rotate: none;
scale: none;
}
:root.ui-mode-fancy .mu-rise-in {
animation-duration: 0.01ms;
}
}