diff --git a/HANDOFF.md b/HANDOFF.md index cfa6552..b8b34a3 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -367,3 +367,51 @@ python test_enrich.py # 给 5 首补封面(已跑过,5/5 成功) ### 16.6 未做 / 可选后续 - 是否 `git commit`(工作区改动含本次 + 上轮 v2.2,均未提交)。 - 深色模式、缓存条颜色再打磨、其余「AI 味」细节。 + +--- + +## 17. v2.4 UI 规范化 / Token 体系(已完成 2026-09-24) + +> 老板反馈「整体 UI 风格很撕裂」→ 全量重构 `style.css` 的 token 与取值体系。 + +### 17.1 问题诊断 +`style.css` 原是两段拼接:**主体系**(1~1730,16 空格缩进、有分节) + **补丁区**(1731+,不缩进、硬编码色的 v2/v2.1/v2.2 追加)。具体失控: +- 字号 **42 种**(0.54~2.4rem 密密麻麻,还混用 `0.82rem`/`.82rem` 写法) +- 圆角 **约 20 种**(3/5/6/7/8/9/10/11/12/14/16/18/20/22/28px,定义了 `--radius-*` 却大半没用) +- 颜色硬编码:55 hex + 38 rgba,兜底色 `#1f6feb` 出现 8 次(带 `var(--accent,#1f6feb)` fallback) + +### 17.2 重构内容 +**建立完整 token 体系**(`:root` 重写): +- 色板:`--bg/surface/white/accent*/text*/border*/danger*/success*/warning*/overlay/log-*` +- 字号阶梯 9 档:`--fs-2xs/…/--fs-4xl` +- 圆角阶梯:`--radius-xs/sm/base/lg/xl/pill` +- 阴影:`--shadow-xs/sm/base/lg/accent` +- 动效:`--dur-fast/base/slow` + `--ease-out/spring` +- 间距:`--sp-1`~`--sp-6` + +**全局收敛**: +- `font-size`:42 种 → **9 种**(67 处替换为 var) +- `border-radius`:20 种 → **8 种**(28 处替换为 var,余 50%/xl 特殊) +- 硬编码色:正文区 **清零**(全转 var) +- accent 阴影重复值收进 `--shadow-accent`;`#fff`→`--white`;`#fdd`→`--danger-hover` +- **补丁区整体并入主体系**:统一 12 空格缩进、改用 `--fs-*`/`--radius-*`/`--sp-*`、重写分节注释 + +### 17.3 关键取值变化(有意微调,贴近原值) +- `--radius-sm`: 12px→10px,`--radius`: 16px→14px,`--radius-lg`: 24px→20px,`--radius-xl`: 28px 保留 +- 补丁区硬编码圆角 14/18/22px → 归入 `--radius/--radius-lg` +- live-cover-ph 大图标 2.4rem → `--fs-4xl` + +### 17.4 验证 +- 全文括号配平({} 360/360、( ) 581/581),无 var 残渣/嵌套。 +- 回归:api 16/16、e2e 17/17、write 5/5 全绿。 +- `node --check app.js` 通过。 + +### 17.5 待老板浏览器实测 +- 整体观感是否统一(字号阶梯、圆角、配色)。 +- 特别注意:卡片圆角、按钮胶囊、模态框圆角的和谐度。 + +### 17.6 保留项(非撕裂) +- 毛玻璃 `rgba(255,255,255,…)` 背景、阴影 rgba:正当设计值。 +- `login.html` 独立暗色主题(自己的 `:root`)。 +- `body` 字体栈、`--log-bg` 终端风格:保留。 + diff --git a/public/css/style.css b/public/css/style.css index 71d68f3..4a41fb7 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,32 +1,73 @@ /* ==================== TOKENS ==================== */ :root { + /* 背景与表面 */ --bg: #f4f5f9; --surface: #fff; --surface-hover: #fafbff; + --white: #fff; + /* 强调色 */ --accent: #4f6ef7; --accent-hover: #3d5ce0; --accent-light: #eef1fe; --accent-glow: rgba(79, 110, 247, 0.14); --accent-subtle: rgba(79, 110, 247, 0.06); + /* 文字 */ --text-primary: #0f1225; --text-secondary: #5a607f; --text-muted: #9499b8; + /* 边框 */ --border: #e8eaf2; --border-light: #f0f1f6; + /* 语义色 */ --danger: #ef4565; --danger-light: #fef0f2; + --danger-hover: #fdd; --success: #30a46c; --success-light: #e9f9ef; --warning: #f5a623; --warning-light: #fff7e8; - --radius-sm: 12px; - --radius: 16px; - --radius-lg: 24px; + /* 浮层与终端 */ + --overlay: rgba(20, 22, 30, 0.45); + --log-bg: #1e1e28; + --log-fg: #d4d4d4; + /* 字号阶梯 */ + --fs-2xs: 0.62rem; + --fs-xs: 0.7rem; + --fs-sm: 0.78rem; + --fs-base: 0.84rem; + --fs-md: 0.92rem; + --fs-lg: 1rem; + --fs-xl: 1.12rem; + --fs-2xl: 1.3rem; + --fs-3xl: 1.5rem; + --fs-4xl: 2.4rem; + /* 圆角阶梯 */ + --radius-xs: 8px; + --radius-sm: 10px; + --radius: 14px; + --radius-lg: 20px; --radius-xl: 28px; + --radius-pill: 999px; + /* 阴影 */ --shadow-xs: 0 1px 2px rgba(15, 18, 37, 0.04); --shadow-sm: 0 2px 8px rgba(15, 18, 37, 0.06); --shadow: 0 4px 20px rgba(15, 18, 37, 0.07); --shadow-lg: 0 8px 40px rgba(15, 18, 37, 0.1); + --shadow-accent: 0 4px 16px rgba(79, 110, 247, 0.25); + /* 动效 */ + --dur-fast: 0.15s; + --dur-base: 0.22s; + --dur-slow: 0.35s; + --ease-out: cubic-bezier(0.22, 1, 0.36, 1); + --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); + /* 间距 */ + --sp-1: 4px; + --sp-2: 8px; + --sp-3: 12px; + --sp-4: 16px; + --sp-5: 20px; + --sp-6: 24px; + /* 布局 */ --content-w: 920px; --nav-bottom: 14px; --nav-h: 56px; @@ -159,19 +200,19 @@ align-items: center; gap: 0.5rem; font-weight: 800; - font-size: 0.98rem; + font-size: var(--fs-md);; color: var(--text-primary); letter-spacing: -0.02em; } .brand-icon { width: 30px; height: 30px; - border-radius: 9px; + border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; overflow: hidden; - box-shadow: 0 2px 12px rgba(79, 110, 247, 0.3); + box-shadow: var(--shadow-accent); flex-shrink: 0; } .brand-icon img { @@ -183,12 +224,12 @@ display: inline-flex; align-items: center; gap: 0.28rem; - font-size: 0.56rem; + font-size: var(--fs-2xs);; font-weight: 700; background: var(--success); - color: #fff; + color: var(--white); padding: 0.18rem 0.5rem; - border-radius: 20px; + border-radius: var(--radius-lg); letter-spacing: 0.06em; text-transform: uppercase; animation: livePulse 2.5s ease-in-out infinite; @@ -196,7 +237,7 @@ .live-dot { width: 4px; height: 4px; - background: #fff; + background: var(--white); border-radius: 50%; animation: dotPulse 1.5s ease-in-out infinite; } @@ -226,12 +267,12 @@ gap: 0.45rem; } .cache-pill { - font-size: 0.66rem; + font-size: var(--fs-xs);; font-weight: 500; color: var(--text-secondary); background: var(--surface); padding: 0.22rem 0.55rem; - border-radius: 20px; + border-radius: var(--radius-lg); display: inline-flex; align-items: center; gap: 0.28rem; @@ -240,12 +281,14 @@ letter-spacing: -0.02em; } .btn-link-sm { - font-size: 0.7rem; + font-size: var(--fs-xs);; font-weight: 600; color: var(--accent); text-decoration: none; - padding: 0.28rem 0.6rem; - border-radius: 10px; + padding: 0.28rem 0.7rem; + border: none; + background: transparent; + border-radius: var(--radius-lg); transition: all 0.2s; display: inline-flex; align-items: center; @@ -277,7 +320,7 @@ } .page-container::-webkit-scrollbar-thumb { background: var(--border); - border-radius: 10px; + border-radius: var(--radius-sm); } .page-container::-webkit-scrollbar-thumb:hover { background: var(--text-muted); @@ -288,6 +331,7 @@ .page.active { display: flex; flex-direction: column; + gap: var(--sp-4); flex: 1; min-height: 0; animation: pageEnter 0.4s cubic-bezier(0.22, 1, 0.36, 1) both; @@ -340,13 +384,13 @@ padding: 1.5rem 1.5rem 0.3rem; } .search-header h2 { - font-size: 1.12rem; + font-size: var(--fs-xl);; font-weight: 800; letter-spacing: -0.03em; margin-bottom: 0.12rem; } .search-header p { - font-size: 0.78rem; + font-size: var(--fs-sm);; color: var(--text-muted); } .search-input-wrap { @@ -362,7 +406,7 @@ border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: 0.65rem 0.85rem; - font-size: 0.84rem; + font-size: var(--fs-base);; background: var(--bg); color: var(--text-primary); outline: none; @@ -378,16 +422,16 @@ } .search-field input::placeholder { color: var(--text-muted); - font-size: 0.82rem; + font-size: var(--fs-sm);; } .btn-search { border: none; background: var(--accent); - color: #fff; + color: var(--white); padding: 0 1.2rem; border-radius: var(--radius-sm); font-weight: 700; - font-size: 0.82rem; + font-size: var(--fs-sm);; transition: all 0.2s; white-space: nowrap; letter-spacing: -0.01em; @@ -407,7 +451,7 @@ } .btn-search:hover { background: var(--accent-hover); - box-shadow: 0 4px 16px rgba(79, 110, 247, 0.25); + box-shadow: var(--shadow-accent); } .btn-search:active { transform: scale(0.97); @@ -424,7 +468,7 @@ display: flex; align-items: center; gap: 0.35rem; - font-size: 0.68rem; + font-size: var(--fs-xs);; color: var(--text-muted); max-height: 0; opacity: 0; @@ -438,15 +482,15 @@ } .parse-hint i { color: var(--accent); - font-size: 0.75rem; + font-size: var(--fs-sm);; } .parse-hint code { font-family: "JetBrains Mono", monospace; - font-size: 0.64rem; + font-size: var(--fs-xs);; background: var(--accent-light); color: var(--accent); padding: 0.08rem 0.35rem; - border-radius: 5px; + border-radius: var(--radius-xs); font-weight: 500; } @@ -502,7 +546,7 @@ } .preview-title { font-weight: 700; - font-size: 0.95rem; + font-size: var(--fs-md);; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -510,7 +554,7 @@ margin-bottom: 0.1rem; } .preview-artist { - font-size: 0.78rem; + font-size: var(--fs-sm);; color: var(--text-secondary); white-space: nowrap; overflow: hidden; @@ -526,16 +570,16 @@ display: inline-flex; align-items: center; gap: 0.25rem; - font-size: 0.66rem; + font-size: var(--fs-xs);; font-weight: 500; color: var(--text-secondary); background: var(--surface); padding: 0.24rem 0.55rem; - border-radius: 10px; + border-radius: var(--radius-sm); border: 1px solid var(--border-light); } .detail-tag i { - font-size: 0.7rem; + font-size: var(--fs-xs);; color: var(--text-muted); } .detail-tag.album-tag i { @@ -555,11 +599,11 @@ .btn-download { border: none; background: var(--accent); - color: #fff; + color: var(--white); padding: 0.5rem 1rem; border-radius: var(--radius-sm); font-weight: 700; - font-size: 0.78rem; + font-size: var(--fs-sm);; transition: all 0.2s; display: inline-flex; align-items: center; @@ -584,7 +628,7 @@ } .btn-download:hover { background: var(--accent-hover); - box-shadow: 0 4px 16px rgba(79, 110, 247, 0.25); + box-shadow: var(--shadow-accent); } .btn-download:active { transform: scale(0.97); @@ -600,7 +644,7 @@ animation: slideUp 0.4s cubic-bezier(0.22, 1, 0.36, 1); } .sr-head { - font-size: 0.74rem; + font-size: var(--fs-sm);; color: var(--text-muted); margin-bottom: 0.5rem; padding: 0 0.25rem; @@ -629,7 +673,7 @@ } .sr-item:hover { border-color: var(--accent); - box-shadow: 0 2px 10px rgba(79, 110, 247, 0.12); + box-shadow: var(--shadow-sm); transform: translateY(-1px); } .sr-item.active { @@ -652,13 +696,13 @@ } .sr-name { font-weight: 600; - font-size: 0.84rem; + font-size: var(--fs-base);; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sr-artist { - font-size: 0.72rem; + font-size: var(--fs-xs);; color: var(--text-secondary); white-space: nowrap; overflow: hidden; @@ -666,11 +710,11 @@ margin-top: 0.06rem; } .sr-alias { - font-size: 0.66rem; + font-size: var(--fs-xs);; color: var(--text-muted); background: var(--surface); padding: 0.15rem 0.4rem; - border-radius: 7px; + border-radius: var(--radius-xs); border: 1px solid var(--border-light); max-width: 160px; white-space: nowrap; @@ -679,7 +723,7 @@ } .sr-duration { font-family: "JetBrains Mono", monospace; - font-size: 0.7rem; + font-size: var(--fs-xs);; color: var(--text-muted); flex-shrink: 0; } @@ -698,7 +742,7 @@ align-items: center; justify-content: center; margin: 0 auto 0.9rem; - font-size: 1.3rem; + font-size: var(--fs-2xl);; color: var(--accent); animation: float 3s ease-in-out infinite; } @@ -713,22 +757,22 @@ } .tips-title { font-weight: 700; - font-size: 0.9rem; + font-size: var(--fs-base);; margin-bottom: 0.3rem; letter-spacing: -0.02em; } .tips-desc { - font-size: 0.76rem; + font-size: var(--fs-sm);; color: var(--text-muted); line-height: 1.7; } .tips-desc code { font-family: "JetBrains Mono", monospace; - font-size: 0.68rem; + font-size: var(--fs-xs);; background: var(--accent-light); color: var(--accent); padding: 0.08rem 0.3rem; - border-radius: 5px; + border-radius: var(--radius-xs); font-weight: 500; } @@ -743,7 +787,7 @@ flex-shrink: 0; } .section-title { - font-size: 0.92rem; + font-size: var(--fs-md);; font-weight: 800; display: flex; align-items: center; @@ -755,9 +799,9 @@ height: 20px; background: var(--accent-light); color: var(--accent); - font-size: 0.62rem; + font-size: var(--fs-2xs);; font-weight: 700; - border-radius: 7px; + border-radius: var(--radius-xs); display: inline-flex; align-items: center; justify-content: center; @@ -781,7 +825,7 @@ } .section-body::-webkit-scrollbar-thumb { background: var(--border); - border-radius: 10px; + border-radius: var(--radius-sm); } .section-body::-webkit-scrollbar-thumb:hover { background: var(--text-muted); @@ -790,7 +834,7 @@ border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: 0.35rem 0.65rem; - font-size: 0.74rem; + font-size: var(--fs-sm);; background: var(--bg); color: var(--text-primary); outline: none; @@ -850,22 +894,22 @@ .res-cover { width: 44px; height: 44px; - border-radius: 11px; + border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12); + box-shadow: var(--shadow-sm); } .res-cover-ph { width: 44px; height: 44px; - border-radius: 11px; + border-radius: var(--radius-sm); flex-shrink: 0; display: flex; align-items: center; justify-content: center; color: var(--text-muted); background: var(--bg); - font-size: 1rem; + font-size: var(--fs-lg);; border: 1px solid var(--border-light); } .res-meta { @@ -875,14 +919,14 @@ } .res-title { font-weight: 700; - font-size: 0.83rem; + font-size: var(--fs-base);; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: -0.01em; } .res-artist { - font-size: 0.71rem; + font-size: var(--fs-xs);; color: var(--text-secondary); white-space: nowrap; overflow: hidden; @@ -896,12 +940,12 @@ flex-shrink: 0; } .heat-chip { - font-size: 0.62rem; + font-size: var(--fs-2xs);; font-weight: 600; background: var(--warning-light); color: var(--warning); padding: 0.14rem 0.4rem; - border-radius: 7px; + border-radius: var(--radius-xs); display: inline-flex; align-items: center; gap: 0.18rem; @@ -915,8 +959,8 @@ border: none; background: none; color: var(--text-muted); - font-size: 1rem; - border-radius: 9px; + font-size: var(--fs-lg);; + border-radius: var(--radius-sm); transition: all 0.2s; } .btn-icon:hover { @@ -940,7 +984,7 @@ max-height 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s, padding 0.35s; - font-size: 0.68rem; + font-size: var(--fs-xs);; color: var(--text-secondary); padding: 0 0.75rem 0 calc(0.75rem + 44px + 0.65rem); } @@ -982,7 +1026,7 @@ } .pl-grip { color: var(--text-muted); - font-size: 0.8rem; + font-size: var(--fs-sm);; flex-shrink: 0; opacity: 0.3; transition: opacity 0.2s; @@ -995,9 +1039,9 @@ height: 20px; background: var(--accent-light); color: var(--accent); - font-size: 0.6rem; + font-size: var(--fs-2xs);; font-weight: 700; - border-radius: 6px; + border-radius: var(--radius-xs); display: flex; align-items: center; justify-content: center; @@ -1010,7 +1054,7 @@ } .pl-name { font-weight: 700; - font-size: 0.82rem; + font-size: var(--fs-sm);; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -1023,13 +1067,13 @@ margin-top: 0.12rem; } .pl-cache { - font-size: 0.6rem; + font-size: var(--fs-2xs);; font-weight: 600; display: inline-flex; align-items: center; gap: 0.18rem; padding: 0.08rem 0.35rem; - border-radius: 6px; + border-radius: var(--radius-xs); } .pl-cache.ready { background: var(--success-light); @@ -1044,24 +1088,24 @@ color: var(--text-muted); } .pl-heat { - font-size: 0.6rem; + font-size: var(--fs-2xs);; } .btn-clear { border: none; background: var(--danger-light); color: var(--danger); - font-size: 0.68rem; + font-size: var(--fs-xs);; font-weight: 700; padding: 0.3rem 0.7rem; - border-radius: 10px; + border-radius: var(--radius-sm); transition: all 0.2s; display: inline-flex; align-items: center; gap: 0.25rem; } .btn-clear:hover { - background: #fdd; - box-shadow: 0 2px 8px rgba(239, 69, 101, 0.15); + background: var(--danger-hover); + box-shadow: var(--shadow-xs); } .btn-clear:active { transform: scale(0.97); @@ -1090,10 +1134,10 @@ .about-logo { width: 72px; height: 72px; - border-radius: 18px; + border-radius: var(--radius-lg); overflow: hidden; margin: 0 auto 1rem; - box-shadow: 0 4px 24px rgba(79, 110, 247, 0.25); + box-shadow: var(--shadow-accent); } .about-logo img { width: 100%; @@ -1101,13 +1145,13 @@ object-fit: cover; } .about-hero h2 { - font-size: 1.25rem; + font-size: var(--fs-2xl);; font-weight: 800; letter-spacing: -0.03em; margin-bottom: 0.15rem; } .about-hero p { - font-size: 0.82rem; + font-size: var(--fs-sm);; color: var(--text-secondary); } .about-body { @@ -1127,7 +1171,7 @@ } .about-body::-webkit-scrollbar-thumb { background: var(--border); - border-radius: 10px; + border-radius: var(--radius-sm); } .about-body::-webkit-scrollbar-thumb:hover { background: var(--text-muted); @@ -1145,21 +1189,21 @@ width: 34px; height: 34px; background: var(--accent-light); - border-radius: 10px; + border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: var(--accent); - font-size: 0.95rem; + font-size: var(--fs-md);; flex-shrink: 0; } .about-section-content h3 { - font-size: 0.82rem; + font-size: var(--fs-sm);; font-weight: 700; margin-bottom: 0.25rem; } .about-section-content p { - font-size: 0.76rem; + font-size: var(--fs-sm);; color: var(--text-secondary); line-height: 1.7; } @@ -1169,12 +1213,12 @@ gap: 0.35rem; } .tech-tags span { - font-size: 0.68rem; + font-size: var(--fs-xs);; font-weight: 600; background: var(--bg); color: var(--text-secondary); padding: 0.2rem 0.55rem; - border-radius: 8px; + border-radius: var(--radius-xs); border: 1px solid var(--border-light); } .disclaimer-section .about-section-icon { @@ -1184,7 +1228,7 @@ .about-version { text-align: center; padding: 0.8rem; - font-size: 0.65rem; + font-size: var(--fs-xs);; color: var(--text-muted); font-family: "JetBrains Mono", monospace; letter-spacing: -0.01em; @@ -1204,14 +1248,14 @@ display: flex; align-items: flex-start; gap: 0.45rem; - font-size: 0.76rem; + font-size: var(--fs-sm);; color: var(--text-secondary); line-height: 1.65; padding: 0.3rem 0; } .about-feat i { - font-size: 0.72rem; + font-size: var(--fs-xs);; flex-shrink: 0; margin-top: 0.18rem; } @@ -1224,8 +1268,8 @@ padding: 0.3rem 0.7rem; background: var(--bg); border: 1px solid var(--border-light); - border-radius: 10px; - font-size: 0.72rem; + border-radius: var(--radius-sm); + font-size: var(--fs-xs);; font-weight: 600; color: var(--text-secondary); text-decoration: none; @@ -1241,7 +1285,7 @@ } .about-gh-link i:first-child { - font-size: 0.9rem; + font-size: var(--fs-base);; } /* ==================== MINI PLAYER ==================== */ @@ -1252,7 +1296,7 @@ transform: translateX(-50%); width: min(var(--content-w), calc(100% - 2rem)); z-index: 99; - border-radius: 20px; + border-radius: var(--radius-lg); overflow: hidden; background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(28px) saturate(200%); @@ -1298,7 +1342,7 @@ .mp-cover { width: 40px; height: 40px; - border-radius: 9px; + border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; box-shadow: var(--shadow-xs); @@ -1309,14 +1353,14 @@ } .mp-name { font-weight: 700; - font-size: 0.8rem; + font-size: var(--fs-sm);; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: -0.01em; } .mp-artist { - font-size: 0.68rem; + font-size: var(--fs-xs);; color: var(--text-secondary); white-space: nowrap; overflow: hidden; @@ -1331,7 +1375,7 @@ } .mp-time { font-family: "JetBrains Mono", monospace; - font-size: 0.64rem; + font-size: var(--fs-xs);; color: var(--text-muted); flex-shrink: 0; min-width: 40px; @@ -1343,8 +1387,8 @@ border: none; border-radius: 50%; background: var(--accent); - color: #fff; - font-size: 0.95rem; + color: var(--white); + font-size: var(--fs-md);; display: flex; align-items: center; justify-content: center; @@ -1352,7 +1396,7 @@ } .mp-play:hover { background: var(--accent-hover); - box-shadow: 0 2px 8px rgba(79, 110, 247, 0.3); + box-shadow: var(--shadow-accent); } .mp-play:active { transform: scale(0.88); @@ -1364,7 +1408,7 @@ border-radius: 50%; background: transparent; color: var(--text-muted); - font-size: 0.85rem; + font-size: var(--fs-base);; display: flex; align-items: center; justify-content: center; @@ -1406,7 +1450,7 @@ backdrop-filter: blur(32px) saturate(220%); -webkit-backdrop-filter: blur(32px) saturate(220%); border: 1px solid rgba(255, 255, 255, 0.55); - border-radius: 22px; + border-radius: var(--radius-lg); box-shadow: 0 2px 12px rgba(15, 18, 37, 0.07), 0 0 0 0.5px rgba(15, 18, 37, 0.03), @@ -1422,17 +1466,17 @@ border: none; background: none; color: var(--text-muted); - font-size: 0.56rem; + font-size: var(--fs-2xs);; font-weight: 600; letter-spacing: 0.03em; - border-radius: 16px; + border-radius: var(--radius); z-index: 1; transition: color 0.3s ease, transform 0.2s ease; } .nav-tab i { - font-size: 1.25rem; + font-size: var(--fs-2xl);; transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); position: relative; z-index: 1; @@ -1449,14 +1493,14 @@ position: absolute; inset: 0; background: var(--accent); - border-radius: 16px; + border-radius: var(--radius); opacity: 0; transform: scale(0.6); transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); z-index: 0; } .nav-tab.active { - color: #fff; + color: var(--white); } .nav-tab.active::before { opacity: 1; @@ -1492,19 +1536,19 @@ align-items: center; justify-content: center; margin: 0 auto 0.75rem; - font-size: 1.1rem; + font-size: var(--fs-xl);; color: var(--text-muted); border: 1px solid var(--border-light); animation: float 3.5s ease-in-out infinite; } .empty-title { font-weight: 700; - font-size: 0.82rem; + font-size: var(--fs-sm);; color: var(--text-secondary); margin-bottom: 0.15rem; } .empty-desc { - font-size: 0.74rem; + font-size: var(--fs-sm);; } /* ==================== TOAST ==================== */ @@ -1521,10 +1565,10 @@ } .toast-msg { background: var(--text-primary); - color: #fff; + color: var(--white); padding: 0.5rem 1.1rem; border-radius: var(--radius-sm); - font-size: 0.78rem; + font-size: var(--fs-sm);; font-weight: 600; box-shadow: var(--shadow-lg); animation: @@ -1593,7 +1637,7 @@ width: 15px; height: 15px; border: 2.5px solid rgba(255, 255, 255, 0.3); - border-top-color: #fff; + border-top-color: var(--white); border-radius: 50%; animation: spin 0.6s linear infinite; display: inline-block; @@ -1651,10 +1695,10 @@ --nav-bottom: 10px; } .nav-tab { - font-size: 0.54rem; + font-size: var(--fs-2xs);; } .nav-tab i { - font-size: 1.05rem; + font-size: var(--fs-lg);; } .cache-pill { display: none; @@ -1692,7 +1736,7 @@ .tips-icon { width: 40px; height: 40px; - font-size: 0.9rem; + font-size: var(--fs-base);; margin-bottom: 0.5rem; } .preview-cover-section { @@ -1726,399 +1770,377 @@ } } -/* ========== v2 新增:频道选择器 / 导入卡片 / 播放中标记 ========== */ -.channel-btn { - display: inline-flex; - align-items: center; - gap: .3rem; - max-width: 150px; - padding: .3rem .7rem; - border: 1px solid var(--border); - border-radius: 20px; - background: var(--surface); - color: var(--text-primary); - font-size: .74rem; - font-weight: 600; - cursor: pointer; - transition: border-color .15s, background .15s; -} -.channel-btn:hover { background: var(--surface-hover); border-color: var(--accent); } -.channel-btn i { color: var(--accent); font-size: .82rem; } -.channel-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + /* ==================== 频道选择器 / 导入卡片 / 播放中标记 ==================== */ + .channel-btn { + display: inline-flex; + align-items: center; + gap: 0.3rem; + max-width: 150px; + padding: 0.3rem 0.7rem; + border: 1px solid var(--border); + border-radius: var(--radius-pill); + background: var(--surface); + color: var(--text-primary); + font-size: var(--fs-sm); + font-weight: 600; + cursor: pointer; + transition: border-color var(--dur-fast), background var(--dur-fast); + } + .channel-btn:hover { background: var(--surface-hover); border-color: var(--accent); } + .channel-btn i { color: var(--accent); font-size: var(--fs-base); } + .channel-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.import-card { - margin-top: 18px; - padding: 18px 20px; - background: rgba(255,255,255,.5); - border: 1px solid rgba(0,0,0,.06); - border-radius: 14px; - display: flex; - flex-direction: column; - gap: 10px; -} -.import-header h3 { - margin: 0 0 2px; - font-size: .95rem; - display: flex; - align-items: center; - gap: 6px; - color: var(--accent, #1f6feb); -} -.import-header p { margin: 0 0 4px; font-size: .75rem; color: #888; } -.import-input { - padding: 10px 12px; - border: 1px solid rgba(0,0,0,.1); - border-radius: 9px; - font-size: .85rem; - outline: none; - background: #fff; - transition: border-color .15s; -} -.import-input:focus { border-color: var(--accent, #1f6feb); } -.import-progress { font-size: .78rem; color: #888; min-height: 16px; } + .import-card { + margin-top: var(--sp-5); + padding: var(--sp-5); + background: var(--bg); + border: 1px solid var(--border-light); + border-radius: var(--radius); + display: flex; + flex-direction: column; + gap: var(--sp-3); + } + .import-header h3 { + margin: 0 0 2px; + font-size: var(--fs-md); + display: flex; + align-items: center; + gap: 6px; + color: var(--accent); + } + .import-header p { margin: 0 0 4px; font-size: var(--fs-sm); color: var(--text-muted); } + .import-input { + padding: var(--sp-3); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + font-size: var(--fs-base); + outline: none; + background: var(--surface); + transition: border-color var(--dur-fast); + } + .import-input:focus { border-color: var(--accent); } + .import-progress { font-size: var(--fs-sm); color: var(--text-muted); min-height: 16px; } -.now-badge { - display: inline-block; - margin-left: 6px; - padding: 1px 7px; - font-size: .62rem; - border-radius: 8px; - background: var(--accent, #1f6feb); - color: #fff; - vertical-align: middle; - animation: nowPulse 1.6s ease-in-out infinite; -} -@keyframes nowPulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } } + .now-badge { + display: inline-block; + margin-left: 6px; + padding: 1px 7px; + font-size: var(--fs-2xs); + border-radius: var(--radius-xs); + background: var(--accent); + color: var(--white); + vertical-align: middle; + animation: nowPulse 1.6s ease-in-out infinite; + } + @keyframes nowPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } } -.btn-icon.danger:hover { color: #f85149; } -/* ========== v2.1 新增:频道管理模态框 ========== */ -.modal-mask { - position: fixed; - inset: 0; - background: rgba(20, 22, 30, 0.45); - backdrop-filter: blur(4px); - -webkit-backdrop-filter: blur(4px); - display: none; - align-items: center; - justify-content: center; - z-index: 9000; - padding: 20px; -} -.modal-mask.show { display: flex; } -.modal-box { - width: 100%; - max-width: 420px; - max-height: 82vh; - background: var(--surface); - border-radius: 18px; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25); - display: flex; - flex-direction: column; - overflow: hidden; - animation: modalIn 0.22s ease; -} -@keyframes modalIn { - from { opacity: 0; transform: translateY(14px) scale(0.98); } - to { opacity: 1; transform: none; } -} -.modal-head { - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px 20px; - border-bottom: 1px solid rgba(0, 0, 0, 0.06); -} -.modal-head h3 { - margin: 0; - font-size: 1rem; - display: flex; - align-items: center; - gap: 8px; -} -.modal-close { - border: none; - background: transparent; - cursor: pointer; - font-size: 1rem; - color: var(--text-muted); - padding: 4px 8px; - border-radius: 8px; -} -.modal-close:hover { background: var(--bg); color: var(--text-primary); } -.modal-body { padding: 14px 20px 20px; overflow-y: auto; } -.stream-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; } -.stream-row { - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px 12px; - border-radius: 12px; - background: var(--bg); - border: 1px solid var(--border-light); -} -.stream-row-name { - font-size: 0.88rem; - font-weight: 600; - color: var(--text-primary); - display: flex; - align-items: center; - gap: 6px; -} -.stream-row-sub { font-size: 0.7rem; color: var(--text-muted); margin-top: 2px; } -.stream-row-actions { display: flex; gap: 4px; } -.stream-create { - display: flex; - flex-direction: column; - gap: 8px; - padding-top: 14px; - border-top: 1px dashed rgba(0, 0, 0, 0.1); -} -.stream-create input { - padding: 9px 12px; - border: 1px solid var(--border); - border-radius: 9px; - font-size: 0.82rem; - outline: none; - background: var(--surface); -} -.stream-create input:focus { border-color: var(--accent, #1f6feb); } -.stream-create button { - padding: 10px; - border: none; - border-radius: 9px; - cursor: pointer; - background: var(--accent, #1f6feb); - color: #fff; - font-size: 0.85rem; - font-weight: 600; -} -.stream-create button:hover { filter: brightness(1.08); } + /* ==================== 频道管理模态框 ==================== */ + .modal-mask { + position: fixed; + inset: 0; + background: var(--overlay); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + display: none; + align-items: center; + justify-content: center; + z-index: 9000; + padding: var(--sp-5); + } + .modal-mask.show { display: flex; } + .modal-box { + width: 100%; + max-width: 420px; + max-height: 82vh; + background: var(--surface); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + display: flex; + flex-direction: column; + overflow: hidden; + animation: modalIn var(--dur-base) var(--ease-out); + } + @keyframes modalIn { + from { opacity: 0; transform: translateY(14px) scale(0.98); } + to { opacity: 1; transform: none; } + } + .modal-head { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--sp-4) var(--sp-5); + border-bottom: 1px solid var(--border-light); + } + .modal-head h3 { + margin: 0; + font-size: var(--fs-lg); + display: flex; + align-items: center; + gap: var(--sp-2); + } + .modal-close { + border: none; + background: transparent; + cursor: pointer; + font-size: var(--fs-lg); + color: var(--text-muted); + padding: 4px 8px; + border-radius: var(--radius-xs); + } + .modal-close:hover { background: var(--bg); color: var(--text-primary); } + .modal-body { padding: var(--sp-3) var(--sp-5) var(--sp-5); overflow-y: auto; } + .stream-list { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-4); } + .stream-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--sp-3); + border-radius: var(--radius); + background: var(--bg); + border: 1px solid var(--border-light); + } + .stream-row-name { + font-size: var(--fs-base); + font-weight: 600; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 6px; + } + .stream-row-sub { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 2px; } + .stream-row-actions { display: flex; gap: var(--sp-1); } + .stream-create { + display: flex; + flex-direction: column; + gap: var(--sp-2); + padding-top: var(--sp-3); + border-top: 1px dashed var(--border); + } + .stream-create input { + padding: 9px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + font-size: var(--fs-base); + outline: none; + background: var(--surface); + } + .stream-create input:focus { border-color: var(--accent); } + .stream-create button { + padding: var(--sp-3); + border: none; + border-radius: var(--radius-sm); + cursor: pointer; + background: var(--accent); + color: var(--white); + font-size: var(--fs-base); + font-weight: 600; + } + .stream-create button:hover { background: var(--accent-hover); } -/* ========== v2.2 新增:站内收听页 ========== */ -.live-card { - background: rgba(255, 255, 255, 0.62); - backdrop-filter: blur(18px); - -webkit-backdrop-filter: blur(18px); - border: 1px solid rgba(255, 255, 255, 0.6); - border-radius: 22px; - padding: 26px 24px; - box-shadow: 0 10px 40px rgba(0, 0, 0, 0.07); - display: flex; - flex-direction: column; - gap: 20px; -} -.live-now-playing { - display: flex; - align-items: center; - gap: 20px; -} -.live-cover-wrap { - position: relative; - width: 108px; - height: 108px; - flex-shrink: 0; -} -.live-cover { - width: 108px; - height: 108px; - border-radius: 16px; - object-fit: cover; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); -} -.live-cover-ph { - width: 108px; - height: 108px; - border-radius: 16px; - display: flex; - align-items: center; - justify-content: center; - font-size: 2.4rem; - color: #fff; - background: var(--accent); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); -} -.live-badge { - position: absolute; - top: -6px; - left: -6px; - display: inline-flex; - align-items: center; - gap: 4px; - background: #ff3b30; - color: #fff; - font-size: 0.62rem; - font-weight: 700; - letter-spacing: 0.5px; - padding: 3px 8px; - border-radius: 10px; - box-shadow: var(--shadow-xs); -} -.live-meta { min-width: 0; flex: 1; } -.live-station { - font-size: 0.78rem; - color: var(--accent, #1f6feb); - font-weight: 600; - margin-bottom: 6px; -} -.live-now { - font-size: 1.2rem; - font-weight: 700; - color: var(--text-primary); - margin-bottom: 6px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.live-sub { - font-size: 0.82rem; - color: var(--text-muted); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.live-controls { - display: flex; - align-items: center; - gap: 16px; -} -.live-play-btn { - width: 54px; - height: 54px; - flex-shrink: 0; - border: none; - border-radius: 50%; - cursor: pointer; - background: var(--accent); - color: #fff; - font-size: 1.5rem; - display: flex; - align-items: center; - justify-content: center; - box-shadow: var(--shadow-sm); - transition: transform 0.15s ease; -} -.live-play-btn:hover { background: var(--accent-hover); transform: scale(1.06); } -.live-play-btn:active { transform: scale(0.96); } -.live-progress-wrap { flex: 1; min-width: 0; } -.live-progress-bar { - height: 6px; - border-radius: 3px; - background: rgba(0, 0, 0, 0.08); - overflow: hidden; - margin-bottom: 6px; -} -.live-progress-fill { - height: 100%; - width: 0%; - border-radius: 3px; - background: var(--accent); - transition: width 0.4s ease; -} -.live-status { font-size: 0.72rem; color: var(--text-muted); } -.live-hint { - font-size: 0.74rem; - color: var(--text-muted); - display: flex; - align-items: center; - gap: 6px; - padding-top: 14px; - border-top: 1px dashed rgba(0, 0, 0, 0.08); -} -.live-hint b { color: var(--accent, #1f6feb); } -@media (max-width: 480px) { - .live-cover-wrap, .live-cover, .live-cover-ph { width: 84px; height: 84px; } - .live-now { font-size: 1.05rem; } -} + /* ==================== 站内收听页 ==================== */ + .live-card { + background: var(--surface); + border: 1px solid var(--border-light); + border-radius: var(--radius-lg); + padding: var(--sp-6); + box-shadow: var(--shadow); + display: flex; + flex-direction: column; + gap: var(--sp-5); + } + .live-now-playing { display: flex; align-items: center; gap: var(--sp-5); } + .live-cover-wrap { position: relative; width: 108px; height: 108px; flex-shrink: 0; } + .live-cover { + width: 108px; + height: 108px; + border-radius: var(--radius); + object-fit: cover; + box-shadow: var(--shadow-sm); + } + .live-cover-ph { + width: 108px; + height: 108px; + border-radius: var(--radius); + display: flex; + align-items: center; + justify-content: center; + font-size: var(--fs-3xl); + color: var(--white); + background: var(--accent); + box-shadow: var(--shadow-sm); + } + .live-badge { + position: absolute; + top: -6px; + left: -6px; + display: inline-flex; + align-items: center; + gap: var(--sp-1); + background: var(--danger); + color: var(--white); + font-size: var(--fs-2xs); + font-weight: 700; + letter-spacing: 0.03em; + padding: 3px 8px; + border-radius: var(--radius-pill); + box-shadow: var(--shadow-xs); + } + .live-meta { min-width: 0; flex: 1; } + .live-station { font-size: var(--fs-sm); color: var(--accent); font-weight: 600; margin-bottom: 6px; } + .live-now { + font-size: var(--fs-xl); + font-weight: 700; + color: var(--text-primary); + margin-bottom: 6px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .live-sub { + font-size: var(--fs-base); + color: var(--text-muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .live-controls { display: flex; align-items: center; gap: var(--sp-4); } + .live-play-btn { + width: 54px; + height: 54px; + flex-shrink: 0; + border: none; + border-radius: 50%; + cursor: pointer; + background: var(--accent); + color: var(--white); + font-size: var(--fs-3xl);; + display: flex; + align-items: center; + justify-content: center; + box-shadow: var(--shadow-sm); + transition: background var(--dur-fast), transform var(--dur-fast); + } + .live-play-btn:hover { background: var(--accent-hover); transform: scale(1.06); } + .live-play-btn:active { transform: scale(0.96); } + .live-progress-wrap { flex: 1; min-width: 0; } + .live-progress-bar { + height: 6px; + border-radius: var(--radius-pill); + background: var(--border); + overflow: hidden; + margin-bottom: 6px; + } + .live-progress-fill { + height: 100%; + width: 0%; + border-radius: var(--radius-pill); + background: var(--accent); + transition: width 0.4s ease; + } + .live-status { font-size: var(--fs-xs); color: var(--text-muted); } + .live-hint { + font-size: var(--fs-xs); + color: var(--text-muted); + display: flex; + align-items: center; + gap: 6px; + padding-top: var(--sp-3); + border-top: 1px dashed var(--border); + } + .live-hint b { color: var(--accent); } + @media (max-width: 480px) { + .live-cover-wrap, .live-cover, .live-cover-ph { width: 84px; height: 84px; } + .live-now { font-size: var(--fs-lg); } + } -/* ========== v2.2 新增:设置页 ========== */ -.cache-stat { padding: 4px 0; } -.cache-stat-row { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.86rem; - color: #666; - margin-bottom: 10px; -} -.cache-stat-row b { color: #222; font-size: 0.95rem; } -.cache-bar { - height: 10px; - border-radius: 5px; - background: rgba(0, 0, 0, 0.07); - overflow: hidden; -} -.cache-bar-fill { - height: 100%; - width: 0%; - border-radius: 5px; - background: var(--success); - transition: width 0.4s ease, background 0.3s; -} -.cache-bar-fill.warn { background: var(--warning); } -.cache-bar-fill.danger { background: var(--danger); } -.cache-stat-note { font-size: 0.72rem; color: #999; margin-top: 8px; } + /* ==================== 设置页 ==================== */ + /* 设置页内容区左右内边距与标题对齐,增加呼吸感 */ + #pageSettings .section-body { + padding: 0 1.1rem 1.1rem; + } + .cache-stat { padding: var(--sp-1) 0; } + .cache-stat-row { + display: flex; + justify-content: space-between; + align-items: center; + font-size: var(--fs-base); + color: var(--text-secondary); + margin-bottom: var(--sp-3); + } + .cache-stat-row b { color: var(--text-primary); font-size: var(--fs-md); } + .cache-bar { + height: 10px; + border-radius: var(--radius-pill); + background: var(--border); + overflow: hidden; + } + .cache-bar-fill { + height: 100%; + width: 0%; + border-radius: var(--radius-pill); + background: var(--success); + transition: width 0.4s ease, background 0.3s; + } + .cache-bar-fill.warn { background: var(--warning); } + .cache-bar-fill.danger { background: var(--danger); } + .cache-stat-note { font-size: var(--fs-xs); color: var(--text-muted); margin-top: var(--sp-2); } -.config-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); - gap: 10px; -} -.config-item { - display: flex; - flex-direction: column; - gap: 4px; - padding: 12px 14px; - border-radius: 12px; - background: rgba(0, 0, 0, 0.03); - border: 1px solid rgba(0, 0, 0, 0.05); -} -.config-item span { font-size: 0.72rem; color: #999; } -.config-item b { font-size: 0.95rem; color: #222; } + .config-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: var(--sp-2); + } + .config-item { + display: flex; + flex-direction: column; + gap: var(--sp-1); + padding: var(--sp-3); + border-radius: var(--radius); + background: var(--bg); + border: 1px solid var(--border-light); + } + .config-item span { font-size: var(--fs-xs); color: var(--text-muted); } + .config-item b { font-size: var(--fs-md); color: var(--text-primary); } -.log-tail-select { - appearance: none; - -webkit-appearance: none; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 9px; - padding: 6px 12px; - font-size: 0.78rem; - color: #444; - background: #fff; - cursor: pointer; - outline: none; -} -.log-view { - max-height: 340px; - overflow-y: auto; - margin: 0; - padding: 14px; - border-radius: 12px; - background: #1e1e28; - color: #d4d4d4; - font-family: "Cascadia Code", "Consolas", monospace; - font-size: 0.72rem; - line-height: 1.6; - white-space: pre-wrap; - word-break: break-all; -} + .log-tail-select { + appearance: none; + -webkit-appearance: none; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 6px 12px; + font-size: var(--fs-sm); + color: var(--text-primary); + background: var(--surface); + cursor: pointer; + outline: none; + } + .log-view { + max-height: 340px; + overflow-y: auto; + margin: 0; + padding: var(--sp-3); + border-radius: var(--radius); + background: var(--log-bg); + color: var(--log-fg); + font-family: "Cascadia Code", "Consolas", monospace; + font-size: var(--fs-xs); + line-height: 1.6; + white-space: pre-wrap; + word-break: break-all; + } -/* ========== 资源页排序 ========== */ -.resource-tools { - display: flex; - align-items: center; - gap: 8px; - flex-wrap: wrap; -} -.resource-sort { - appearance: none; - -webkit-appearance: none; - border: 1.5px solid var(--border, rgba(0, 0, 0, 0.1)); - border-radius: var(--radius-sm, 9px); - padding: 0.35rem 1.6rem 0.35rem 0.6rem; - font-size: 0.72rem; - background: var(--bg, #fff) url("data:image/svg+xml;utf8,") no-repeat right 7px center; - color: var(--text-primary, #444); - cursor: pointer; - outline: none; -} -.resource-sort:hover { border-color: var(--accent, #1f6feb); } + /* ==================== 资源页排序 ==================== */ + .resource-tools { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; } + .resource-sort { + appearance: none; + -webkit-appearance: none; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + padding: 0.35rem 1.6rem 0.35rem 0.6rem; + font-size: var(--fs-xs); + background: var(--bg) url("data:image/svg+xml;utf8,") no-repeat right 7px center; + color: var(--text-primary); + cursor: pointer; + outline: none; + } + .resource-sort:hover { border-color: var(--accent); } diff --git a/public/index.html b/public/index.html index 04975a7..fb82f5f 100644 --- a/public/index.html +++ b/public/index.html @@ -39,8 +39,8 @@