video-shuoshan/web/src/index.css
seaislee1209 f0f47e8368 feat(theme): 亮色主题切换完整实现 — dark/light 双套 var + Sidebar 切换 + 浅色色板
Stage 1 (var 化, 350 处): 425 处硬编码颜色 → CSS var, 涉及 49 个 tsx/css module 文件,
   按 hot files (DashboardPage/TeamDashboardPage/RecordDetailModal/ReferenceList) →
   Modal/Asset/Profile/Login → 生成页家族/管理后台/公共 UI 三波 8 个 sub-agent 并行处理。
   index.css :root 加 ~70 个新 var (modal/text 层级/状态色 bg 变体/chart/mention pill 等)。
Stage 2 (双套 var): :root 保留 DARK 默认值, [data-theme="light"] 覆盖 ~95 个 token。
   浅色色板按 Vercel Geist (#fafafa / #171717 / shadow-border) + Linear Light surface 分层规范,
   主色 #6c63ff → #5048cc 加深 18% 满足 WCAG AA。aurora 极光在 light 下 display:none。
Stage 3 (切换机制): 新建 store/theme.ts (Zustand + localStorage 持久化),
   Sidebar 加月亮/太阳 SVG 切换按钮 (位于头像上方),
   DashboardPage/TeamDashboardPage/ProfilePage 的 ECharts 配 key={theme} 强制重渲染。
Stage 4 (微调): LandingPage 强制 data-theme="dark" 保持品牌识别 (登录流程一直深色),
   sidebar bg / card bg / border 在浅色下加深 0.02 提升轮廓辨识度。
Stage 5 (验证): Playwright 头无浏览器自动登录 admin + screenshot_user, 截深/浅各 12 个页面 = 24 张
   到 docs/screenshots/ (本地档, .gitignore 排除 png 不入库)。
   vitest 71fail/162pass 与改造前基线完全一致, 无新增回归。

完成报告: docs/todo/亮色主题切换-完成报告.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:10:35 +08:00

529 lines
19 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap');
/* ═══════════════════════════════════════════════════════════════
THEME TOKENS
:root → layout / sizing (theme-agnostic) + default DARK colors
[data-theme="light"] → light overrides
切换由 web/src/store/theme.ts 写到 <html data-theme="dark|light">
═══════════════════════════════════════════════════════════════ */
:root {
/* ── Layout / sizing (theme-agnostic) ── */
--radius-card: 12px;
--sidebar-width: 240px;
--sidebar-collapsed-width: 64px;
--radius-input-bar: 20px;
--radius-btn: 8px;
--radius-send-btn: 50%;
--radius-thumbnail: 8px;
--radius-dropdown: 12px;
--input-bar-max-width: 950px;
--send-btn-size: 36px;
--thumbnail-size: 80px;
--toolbar-height: 44px;
--toolbar-btn-height: 32px;
/* ══════════════════════════════════════════════
DEFAULT = DARK THEME COLORS
══════════════════════════════════════════════ */
--color-bg-page: #07070f;
--color-bg-input-bar: rgba(255, 255, 255, 0.06);
--color-border-input-bar: rgba(255, 255, 255, 0.10);
--color-primary: #6c63ff;
--color-text-primary: #f1f0ff;
--color-text-secondary: #8b8ea8;
--color-text-disabled: #4c4f6b;
--color-bg-hover: rgba(255, 255, 255, 0.08);
--color-bg-dropdown: rgba(13, 13, 26, 0.92);
--color-bg-upload: rgba(255, 255, 255, 0.04);
--color-border-upload: rgba(255, 255, 255, 0.08);
--color-btn-send-disabled: #3a3a4a;
--color-btn-send-active: #6c63ff;
--color-sidebar-bg: rgba(7, 7, 15, 0.80);
--color-bg-sidebar: rgba(7, 7, 15, 0.80);
--color-sidebar-active: rgba(255, 255, 255, 0.08);
--color-sidebar-hover: rgba(255, 255, 255, 0.04);
--color-bg-card: rgba(255, 255, 255, 0.06);
--color-border-card: rgba(255, 255, 255, 0.10);
--color-success: #00b894;
--color-danger: #e74c3c;
--color-warning: #f39c12;
/* Modal & overlay */
--color-modal-overlay: rgba(0, 0, 0, 0.6);
--color-overlay-strong: rgba(0, 0, 0, 0.7);
--color-bg-modal: #111118;
--color-bg-modal-elevated: #16161e;
--color-bg-modal-glass: rgba(22, 22, 30, 0.92);
--color-bg-elevated: #0a0a0f;
--color-bg-placeholder: #1a1a2e;
--color-bg-dropdown-elevated: #1a1a24;
--color-bg-video: #000;
--color-border-modal: #2a2a38;
--color-border-modal-soft: rgba(255, 255, 255, 0.08);
--color-border-soft: rgba(255, 255, 255, 0.06);
--color-border-row: rgba(255, 255, 255, 0.04);
--color-shadow-modal: rgba(0, 0, 0, 0.6);
--color-shadow-dropdown: rgba(0, 0, 0, 0.4);
/* Text variants */
--color-text-tertiary: #888;
--color-text-quaternary: #555;
--color-text-light: #e2e2ea;
--color-text-monochrome: #ccc;
--color-text-on-glass: rgba(255, 255, 255, 0.7);
--color-text-on-glass-soft: rgba(255, 255, 255, 0.5);
--color-text-on-glass-faint: rgba(255, 255, 255, 0.4);
/* Status accents */
--color-info: #00b8e6;
--color-purple-accent: #a78bfa;
--color-danger-text: #ef4444;
--color-success-bg: rgba(0, 184, 148, 0.15);
--color-success-bg-hover: rgba(0, 184, 148, 0.10);
--color-info-bg: rgba(0, 184, 230, 0.15);
--color-info-bg-hover: rgba(0, 184, 230, 0.10);
--color-info-bg-soft: rgba(0, 184, 230, 0.12);
--color-danger-bg: rgba(231, 76, 60, 0.15);
--color-danger-bg-hover: rgba(231, 76, 60, 0.10);
--color-danger-bg-soft: rgba(231, 76, 60, 0.08);
--color-danger-border: rgba(231, 76, 60, 0.20);
--color-purple-bg: rgba(167, 139, 250, 0.15);
--color-purple-bg-hover: rgba(167, 139, 250, 0.10);
/* Charts */
--color-tooltip-bg: rgba(13, 13, 26, 0.95);
--color-tooltip-border: rgba(255, 255, 255, 0.10);
--color-chart-axis: rgba(255, 255, 255, 0.08);
--color-chart-grid: rgba(255, 255, 255, 0.06);
--color-chart-area-from: rgba(108, 99, 255, 0.25);
--color-chart-area-to: rgba(108, 99, 255, 0.02);
--color-accent-2: #06d6a0;
--color-primary-2: #8b5cf6;
/* Misc */
--color-progress-track: rgba(255, 255, 255, 0.2);
--color-on-primary: #fff;
--color-on-overlay: #fff;
/* Brand mint accent (Auth modals) */
--color-mint-accent: #7edcc8;
--color-mint-accent-bg: rgba(120, 220, 200, 0.12);
--color-mint-accent-bg-hover: rgba(120, 220, 200, 0.22);
--color-mint-accent-border: rgba(120, 220, 200, 0.30);
--color-mint-accent-glow: rgba(120, 220, 200, 0.15);
/* Warning bg variants */
--color-warning-bg: rgba(243, 156, 18, 0.12);
--color-warning-bg-hover: rgba(243, 156, 18, 0.18);
--color-warning-border: rgba(243, 156, 18, 0.30);
/* Primary alpha hover */
--color-primary-bg: rgba(108, 99, 255, 0.04);
--color-primary-bg-hover: rgba(108, 99, 255, 0.08);
/* Generic overlay tiers */
--color-overlay-soft: rgba(0, 0, 0, 0.5);
--color-overlay-medium: rgba(0, 0, 0, 0.3);
--color-overlay-faint: rgba(0, 0, 0, 0.15);
/* Modal/upload trigger hover surfaces */
--color-border-modal-hover: #5a5a6a;
--color-bg-modal-hover: #1e1e2a;
/* Inset highlight (glass surfaces) */
--color-inset-highlight: rgba(255, 255, 255, 0.05);
--color-inset-highlight-strong: rgba(255, 255, 255, 0.12);
/* @ Mention pill */
--color-mention-bg: rgba(108, 99, 255, 0.12);
--color-mention-bg-hover: rgba(108, 99, 255, 0.22);
--color-mention-bg-active: rgba(108, 99, 255, 0.15);
--color-mention-text: rgba(108, 99, 255, 0.7);
--color-mention-text-hover: rgba(108, 99, 255, 0.9);
/* Shimmer */
--color-shimmer-purple-soft: rgba(108, 99, 255, 0.03);
--color-shimmer-purple-mid: rgba(108, 99, 255, 0.08);
--color-shimmer-purple-2-mid: rgba(139, 92, 246, 0.12);
/* Brighter danger */
--color-danger-hover: #ff6b6b;
--color-danger-hover-bg: rgba(255, 107, 107, 0.08);
--color-danger-hover-bg-strong: rgba(255, 107, 107, 0.10);
--color-danger-hover-border: rgba(255, 107, 107, 0.30);
/* Info hover (brighter cyan) */
--color-info-hover: #00ccff;
--color-info-hover-2: #33ccf0;
--color-info-shadow-soft: rgba(0, 184, 230, 0.30);
--color-info-shadow-strong: rgba(0, 184, 230, 0.50);
/* Lightbox / extra-deep overlay */
--color-overlay-deep: rgba(0, 0, 0, 0.85);
/* White alpha utility */
--color-bg-on-media: rgba(255, 255, 255, 0.15);
--color-bg-on-media-hover: rgba(255, 255, 255, 0.25);
/* Toast warning */
--color-warning-toast: #e8952e;
/* Scrollbar thumb */
--color-scrollbar-thumb: rgba(255, 255, 255, 0.10);
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.20);
/* Aurora / decorative bg layers */
--color-aurora-1: rgba(108, 99, 255, 0.6);
--color-aurora-2: rgba(59, 130, 246, 0.5);
--color-aurora-3: rgba(139, 92, 246, 0.35);
--color-cursor-glow: rgba(108, 99, 255, 0.06);
--color-grid-line: rgba(255, 255, 255, 0.02);
}
/* ══════════════════════════════════════════════
LIGHT THEME OVERRIDES
规范来源: Vercel Geist (#fafafa / #171717 / 阴影边框) + Linear (#f3f4f5 surface)
主色加深 18% 满足 WCAG AA 对比度
══════════════════════════════════════════════ */
[data-theme="light"] {
/* Page surfaces — Vercel Gray 50 + 纯白 modal */
--color-bg-page: #fafafa;
--color-bg-input-bar: #ffffff;
--color-bg-dropdown: rgba(255, 255, 255, 0.96);
/* 卡片背景加深至 0.05,配合更强的 border 在 #fafafa 上有清晰轮廓 */
--color-bg-upload: rgba(0, 0, 0, 0.03);
--color-bg-card: rgba(0, 0, 0, 0.05);
--color-bg-hover: rgba(0, 0, 0, 0.07);
/* Sidebar 加深一档,避免在浅色 page bg 上完全融入消失 */
--color-sidebar-bg: rgba(243, 244, 246, 0.92);
--color-bg-sidebar: rgba(243, 244, 246, 0.92);
--color-sidebar-active: rgba(0, 0, 0, 0.08);
--color-sidebar-hover: rgba(0, 0, 0, 0.05);
/* Borders — Vercel shadow-border 风格,整体加深 0.02 提升浅色下卡片轮廓 */
--color-border-input-bar: rgba(0, 0, 0, 0.12);
--color-border-card: rgba(0, 0, 0, 0.10);
--color-border-upload: rgba(0, 0, 0, 0.08);
--color-border-modal: #e5e7eb;
--color-border-modal-soft: rgba(0, 0, 0, 0.08);
--color-border-modal-hover: #9ca3af;
--color-border-soft: rgba(0, 0, 0, 0.06);
--color-border-row: rgba(0, 0, 0, 0.05);
/* Text — Vercel 灰阶 #171717 / #4d4d4d / #888 / #cbd5e1 */
--color-text-primary: #171823;
--color-text-secondary: #6b6e85;
--color-text-tertiary: #9ca3af;
--color-text-quaternary: #cbd5e1;
--color-text-disabled: #cbd5e1;
--color-text-light: #374151;
--color-text-monochrome: #4b5563;
--color-text-on-glass: rgba(0, 0, 0, 0.75);
--color-text-on-glass-soft: rgba(0, 0, 0, 0.55);
--color-text-on-glass-faint: rgba(0, 0, 0, 0.40);
/* Brand — 主色加深 18% (#6c63ff → #5048cc) */
--color-primary: #5048cc;
--color-primary-2: #7c3aed;
--color-primary-bg: rgba(80, 72, 204, 0.06);
--color-primary-bg-hover: rgba(80, 72, 204, 0.10);
--color-btn-send-active: #5048cc;
--color-btn-send-disabled: #d1d5db;
/* Status — 全部加深保持 AA 对比度 */
--color-success: #00a37e;
--color-danger: #d63a2a;
--color-warning: #d4860a;
--color-info: #0099cc;
--color-purple-accent: #7c3aed;
--color-success-bg: rgba(0, 163, 126, 0.10);
--color-success-bg-hover: rgba(0, 163, 126, 0.06);
--color-info-bg: rgba(0, 153, 204, 0.10);
--color-info-bg-hover: rgba(0, 153, 204, 0.06);
--color-info-bg-soft: rgba(0, 153, 204, 0.08);
--color-danger-bg: rgba(214, 58, 42, 0.10);
--color-danger-bg-hover: rgba(214, 58, 42, 0.06);
--color-danger-bg-soft: rgba(214, 58, 42, 0.05);
--color-danger-border: rgba(214, 58, 42, 0.18);
--color-danger-text: #dc2626;
--color-warning-bg: rgba(212, 134, 10, 0.10);
--color-warning-bg-hover: rgba(212, 134, 10, 0.06);
--color-warning-border: rgba(212, 134, 10, 0.25);
--color-warning-toast: #c97a1c;
--color-purple-bg: rgba(124, 58, 237, 0.10);
--color-purple-bg-hover: rgba(124, 58, 237, 0.06);
/* Modal & overlay — 浅色下整体减弱 */
--color-modal-overlay: rgba(0, 0, 0, 0.20);
--color-overlay-strong: rgba(0, 0, 0, 0.30);
--color-overlay-soft: rgba(0, 0, 0, 0.18);
--color-overlay-medium: rgba(0, 0, 0, 0.12);
--color-overlay-faint: rgba(0, 0, 0, 0.08);
--color-overlay-deep: rgba(0, 0, 0, 0.45);
--color-bg-modal: #ffffff;
--color-bg-modal-elevated: #ffffff;
--color-bg-modal-glass: rgba(255, 255, 255, 0.92);
--color-bg-modal-hover: #f5f5f5;
--color-bg-elevated: #f3f4f5;
--color-bg-placeholder: #ebebeb;
--color-bg-dropdown-elevated: #ffffff;
--color-bg-video: #000;
--color-shadow-modal: rgba(0, 0, 0, 0.10);
--color-shadow-dropdown: rgba(0, 0, 0, 0.08);
/* Charts — 浅色 tooltip 用白底 */
--color-tooltip-bg: rgba(255, 255, 255, 0.98);
--color-tooltip-border: rgba(0, 0, 0, 0.10);
--color-chart-axis: rgba(0, 0, 0, 0.10);
--color-chart-grid: rgba(0, 0, 0, 0.06);
--color-chart-area-from: rgba(80, 72, 204, 0.20);
--color-chart-area-to: rgba(80, 72, 204, 0.02);
--color-accent-2: #059669;
/* Misc */
--color-progress-track: rgba(0, 0, 0, 0.10);
--color-on-primary: #ffffff;
--color-on-overlay: #ffffff;
/* Brand mint accent (Auth modals) — deepen to teal in light */
--color-mint-accent: #0d9488;
--color-mint-accent-bg: rgba(13, 148, 136, 0.08);
--color-mint-accent-bg-hover: rgba(13, 148, 136, 0.14);
--color-mint-accent-border: rgba(13, 148, 136, 0.30);
--color-mint-accent-glow: rgba(13, 148, 136, 0.18);
/* Inset highlight (浅色下用淡黑半透明做 inset) */
--color-inset-highlight: rgba(0, 0, 0, 0.04);
--color-inset-highlight-strong: rgba(0, 0, 0, 0.06);
/* Mention pill */
--color-mention-bg: rgba(80, 72, 204, 0.10);
--color-mention-bg-hover: rgba(80, 72, 204, 0.16);
--color-mention-bg-active: rgba(80, 72, 204, 0.12);
--color-mention-text: #5048cc;
--color-mention-text-hover: #3a3380;
/* Shimmer */
--color-shimmer-purple-soft: rgba(80, 72, 204, 0.03);
--color-shimmer-purple-mid: rgba(80, 72, 204, 0.06);
--color-shimmer-purple-2-mid: rgba(124, 58, 237, 0.08);
/* Danger hover (brighter red) */
--color-danger-hover: #ef4444;
--color-danger-hover-bg: rgba(239, 68, 68, 0.06);
--color-danger-hover-bg-strong: rgba(239, 68, 68, 0.08);
--color-danger-hover-border: rgba(239, 68, 68, 0.20);
/* Info hover */
--color-info-hover: #0088b8;
--color-info-hover-2: #1aa9d4;
--color-info-shadow-soft: rgba(0, 153, 204, 0.20);
--color-info-shadow-strong: rgba(0, 153, 204, 0.35);
/* White alpha on dark media — 保留白色徽章语义 */
--color-bg-on-media: rgba(255, 255, 255, 0.90);
--color-bg-on-media-hover: rgba(255, 255, 255, 1.0);
/* Scrollbar */
--color-scrollbar-thumb: rgba(0, 0, 0, 0.15);
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.30);
/* Aurora 在浅色下隐藏(下面有规则),但 var 也置弱以防万一 */
--color-aurora-1: transparent;
--color-aurora-2: transparent;
--color-aurora-3: transparent;
--color-cursor-glow: rgba(80, 72, 204, 0.04);
--color-grid-line: rgba(0, 0, 0, 0.025);
}
/* 浅色下隐藏 aurora 极光层(白底 + 极光会刺眼,纯净白更"高级" */
[data-theme="light"] .aurora-bg,
[data-theme="light"] .aurora-blob-3 {
display: none;
}
/* ═══════════════════════════════════════════
Reset / globals
═══════════════════════════════════════════ */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, #root {
height: 100%;
overflow: hidden;
}
body {
font-family: 'Noto Sans SC', system-ui, -apple-system, sans-serif;
background: var(--color-bg-page);
color: var(--color-text-primary);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Scrollbar: Firefox */
* {
scrollbar-width: thin;
scrollbar-color: transparent transparent;
}
*:hover {
scrollbar-color: var(--color-scrollbar-thumb) transparent;
}
/* Scrollbar: Webkit — hidden by default, visible on hover */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: transparent;
border-radius: 3px;
transition: background 0.2s;
}
*:hover::-webkit-scrollbar-thumb {
background: var(--color-scrollbar-thumb);
}
*:hover::-webkit-scrollbar-thumb:hover {
background: var(--color-scrollbar-thumb-hover);
}
/* ═══════════════════════════════════════════
LAYER 1: Aurora Gradient Background
═══════════════════════════════════════════ */
.aurora-bg {
position: fixed;
inset: 0;
z-index: 0;
overflow: hidden;
pointer-events: none;
}
.aurora-bg::before,
.aurora-bg::after {
content: "";
position: absolute;
border-radius: 50%;
filter: blur(110px);
opacity: 0.4;
will-change: transform;
}
.aurora-bg::before {
width: 600px;
height: 600px;
top: -10%;
right: -5%;
background: radial-gradient(circle, var(--color-aurora-1) 0%, transparent 70%);
animation: aurora-drift-1 20s ease-in-out infinite alternate;
}
.aurora-bg::after {
width: 500px;
height: 500px;
bottom: -5%;
left: -5%;
background: radial-gradient(circle, var(--color-aurora-2) 0%, transparent 70%);
animation: aurora-drift-2 25s ease-in-out infinite alternate;
}
@keyframes aurora-drift-1 {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(-15vw, 10vh) scale(1.1); }
66% { transform: translate(-5vw, 25vh) scale(0.95); }
100% { transform: translate(-20vw, 15vh) scale(1.05); }
}
@keyframes aurora-drift-2 {
0% { transform: translate(0, 0) scale(1); }
33% { transform: translate(10vw, -15vh) scale(1.15); }
66% { transform: translate(20vw, -5vh) scale(0.9); }
100% { transform: translate(15vw, -20vh) scale(1.1); }
}
.aurora-blob-3 {
position: absolute;
width: 400px;
height: 400px;
top: 40%;
left: 50%;
border-radius: 50%;
background: radial-gradient(circle, var(--color-aurora-3) 0%, transparent 70%);
filter: blur(100px);
opacity: 0.3;
will-change: transform;
animation: aurora-drift-3 30s ease-in-out infinite alternate;
pointer-events: none;
}
@keyframes aurora-drift-3 {
0% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-30%, -60%) scale(1.2); }
100% { transform: translate(-70%, -40%) scale(0.85); }
}
/* ═══════════════════════════════════════════
LAYER 2: Noise Texture Overlay
═══════════════════════════════════════════ */
.noise-overlay {
position: fixed;
inset: 0;
z-index: 1;
pointer-events: none;
opacity: 0.03;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 256px 256px;
}
/* ═══════════════════════════════════════════
LAYER 3: Mouse-tracking Glow
═══════════════════════════════════════════ */
.cursor-glow {
position: fixed;
inset: 0;
z-index: 1;
pointer-events: none;
background: radial-gradient(
600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
var(--color-cursor-glow) 0%,
transparent 60%
);
transition: opacity 0.3s ease;
}
/* ═══════════════════════════════════════════
LAYER 4: Subtle grid pattern
═══════════════════════════════════════════ */
.grid-pattern {
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
background-image:
linear-gradient(var(--color-grid-line) 1px, transparent 1px),
linear-gradient(90deg, var(--color-grid-line) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 20%, transparent 100%);
-webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 20%, transparent 100%);
}
/* ═══════════════════════════════════════════
Reduced motion
═══════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
.aurora-bg::before,
.aurora-bg::after,
.aurora-blob-3 {
animation: none !important;
opacity: 0.2 !important;
}
}