- 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 项(真点击/真持久化/ 真指针事件);变异反证(去掉读回 → 持久化往返必红)
396 lines
14 KiB
CSS
396 lines
14 KiB
CSS
@import "../design/tokens.css";
|
||
@import "tailwindcss";
|
||
|
||
/* 让 Tailwind 通过对 token 的映射生成工具类(bg-surface-1 / rounded-smooth / ease-spring 等)。
|
||
tokens.css 里的 surface 是动态值(Light 会覆盖),这里用静态 hex 生成工具类。 */
|
||
@theme {
|
||
--color-surface-1: #161616;
|
||
--color-surface-2: #0c0c0c;
|
||
--color-surface-3: #1c1c1c;
|
||
--color-surface-4: #242424;
|
||
--color-surface-5: #2c2c2c;
|
||
|
||
--color-text-hi: #f5f5f7;
|
||
--color-text-mid: #b4b4b8;
|
||
--color-text-lo: #7a7a80;
|
||
|
||
--color-accent: #3d6bff;
|
||
--color-accent-hi: #6a8dff;
|
||
--color-ok: #35c26b;
|
||
--color-warn: #ff9f43;
|
||
--color-err: #ff5c5c;
|
||
|
||
--radius-smooth: 0.625rem;
|
||
--radius-pill: 62.5rem;
|
||
|
||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
--ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);
|
||
}
|
||
|
||
html,
|
||
body,
|
||
#root {
|
||
height: 100%;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--mu-surface-2);
|
||
color: var(--mu-text-hi);
|
||
font-family:
|
||
"MiSans",
|
||
system-ui,
|
||
-apple-system,
|
||
"PingFang SC",
|
||
"Microsoft YaHei",
|
||
sans-serif;
|
||
-webkit-font-smoothing: antialiased;
|
||
text-rendering: optimizeLegibility;
|
||
overscroll-behavior: none;
|
||
}
|
||
|
||
/* 毛玻璃表面 —— TopBar / Sidebar / BottomNav 用 */
|
||
.glass {
|
||
background: color-mix(in srgb, var(--mu-surface-1) calc(var(--mu-glass-alpha) * 100%), transparent);
|
||
backdrop-filter: blur(var(--mu-glass-blur)) saturate(1.4);
|
||
-webkit-backdrop-filter: blur(var(--mu-glass-blur)) saturate(1.4);
|
||
border: 1px solid var(--mu-glass-border);
|
||
}
|
||
|
||
/* Liquid Glass 寓意:内高光 + 折射描边 + 深层玻璃阴影 */
|
||
.liquid-glass {
|
||
position: relative;
|
||
background:
|
||
linear-gradient(135deg, var(--mu-liquid-highlight), transparent 42%),
|
||
color-mix(in srgb, var(--mu-surface-4) 88%, transparent);
|
||
box-shadow:
|
||
var(--mu-shadow-2),
|
||
inset 0 1px 0 var(--mu-liquid-rim),
|
||
inset 0 0 0 1px var(--mu-liquid-rim);
|
||
backdrop-filter: blur(var(--mu-glass-blur)) saturate(1.3);
|
||
-webkit-backdrop-filter: blur(var(--mu-glass-blur)) saturate(1.3);
|
||
transition: transform 0.4s var(--mu-spring), box-shadow 0.4s var(--mu-ease);
|
||
}
|
||
.liquid-glass:hover {
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--mu-shadow-3), inset 0 1px 0 var(--mu-liquid-rim);
|
||
}
|
||
|
||
/* 轻量液态玻璃毛玻璃 —— 聊天气泡:半透明(透出底层背景)+ 内高光/折射描边 +
|
||
适度的 backdrop blur 把透出的背景柔化成毛玻璃。主人要求"气泡能隐约看到背景"。
|
||
不透明度 ~68%,blur 中等,既透背景又不影响文字可读。 */
|
||
.liquid-glass-soft {
|
||
position: relative;
|
||
background:
|
||
linear-gradient(135deg, rgba(255,255,255,0.07), transparent 45%),
|
||
color-mix(in srgb, var(--mu-surface-3) 68%, transparent);
|
||
box-shadow:
|
||
inset 0 1px 0 rgba(255,255,255,0.04),
|
||
inset 0 0 0 1px rgba(255,255,255,0.03);
|
||
backdrop-filter: blur(8px) saturate(1.15);
|
||
-webkit-backdrop-filter: blur(8px) saturate(1.15);
|
||
}
|
||
|
||
/* 用户气泡的半透明毛玻璃 —— accent 主色压到 ~76%(白字仍可读),
|
||
透出背景 + blur 柔化;内高光/折射描边保留、边线弱(不刺眼)。 */
|
||
.liquid-glass-accent {
|
||
position: relative;
|
||
background:
|
||
linear-gradient(135deg, rgba(255,255,255,0.07), transparent 45%),
|
||
linear-gradient(180deg, color-mix(in srgb, var(--mu-accent) 76%, transparent), color-mix(in srgb, var(--mu-accent) 72%, transparent));
|
||
box-shadow:
|
||
inset 0 1px 0 rgba(255,255,255,0.04),
|
||
inset 0 0 0 1px rgba(255,255,255,0.03);
|
||
backdrop-filter: blur(8px) saturate(1.2);
|
||
-webkit-backdrop-filter: blur(8px) saturate(1.2);
|
||
}
|
||
|
||
/* Smooth Corner 优先:全局圆角走 token(k=0.55 近似值),落地在组件里用 rounded-smooth */
|
||
* {
|
||
border-radius: var(--mu-radius);
|
||
scrollbar-width: thin;
|
||
scrollbar-color: var(--mu-surface-5) transparent;
|
||
}
|
||
*::-webkit-scrollbar {
|
||
width: 8px;
|
||
height: 8px;
|
||
}
|
||
*::-webkit-scrollbar-thumb {
|
||
background: var(--mu-surface-5);
|
||
border-radius: var(--mu-radius-pill);
|
||
}
|
||
*::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
button {
|
||
font: inherit;
|
||
color: inherit;
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
}
|
||
input,
|
||
textarea {
|
||
font: inherit;
|
||
color: inherit;
|
||
}
|
||
|
||
/* 欢迎出现动画(仅交互/入场) */
|
||
@keyframes mu-rise-in {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(10px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
.mu-rise-in {
|
||
animation: mu-rise-in 0.36s var(--mu-spring) both;
|
||
}
|
||
|
||
/* 思维链呼吸点 */
|
||
@keyframes mu-blink {
|
||
0%,
|
||
100% {
|
||
opacity: 0.35;
|
||
}
|
||
50% {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
.mu-blink {
|
||
animation: mu-blink 1.2s ease-in-out infinite;
|
||
}
|
||
|
||
/* 唤醒上升(静息 → 唤醒 → 全能)的短暂光芒:弹簧过冲 + 脉动光晕。
|
||
仅用于 capacity_awaken 状态徽标 / 唤醒路径当前节点,避免常态动画。 */
|
||
@keyframes mu-awaken {
|
||
0% {
|
||
box-shadow: 0 0 0 0 color-mix(in srgb, var(--mu-accent) 0%, transparent);
|
||
}
|
||
40% {
|
||
transform: scale(1.05);
|
||
box-shadow: 0 0 0 4px color-mix(in srgb, var(--mu-accent) 32%, transparent);
|
||
}
|
||
100% {
|
||
box-shadow: 0 0 0 0 color-mix(in srgb, var(--mu-accent) 0%, transparent);
|
||
}
|
||
}
|
||
.mu-awaken {
|
||
animation: mu-awaken 1.2s var(--mu-spring) ease-in-out;
|
||
}
|
||
|
||
/* 移动端抽屉(MobileNav)滑入:从左侧收起,弹簧过冲,仅一次性入场 */
|
||
@keyframes mu-drawer-in {
|
||
from {
|
||
transform: translateX(-100%);
|
||
}
|
||
to {
|
||
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;
|
||
}
|
||
}
|