diff --git a/static/css/style.css b/static/css/style.css index 7065980..8a6fc2a 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -1,24 +1,143 @@ -/* ===== 全局变量 ===== */ +/* ===== 主题变量 ===== */ :root { + /* 明亮模式 - 暖纸色文学风 */ --bg-primary: #f8f5f0; --bg-card: #ffffff; - --bg-hero: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --bg-secondary: #f0ebe3; + --bg-hero: linear-gradient(135deg, #8B6914 0%, #c17b4a 50%, #a05c2c 100%); + --bg-hero-overlay: rgba(255, 255, 255, 0.04); + --text-primary: #2c2416; --text-secondary: #6b5d4f; --text-light: #9b8e80; + --accent: #c17b4a; --accent-light: #e8a87c; + --accent-dark: #a05c2c; + --accent-bg: rgba(193, 123, 74, 0.08); + --accent-bg-hover: rgba(193, 123, 74, 0.12); + + --border: #e8e0d4; + --border-light: #f0ebe3; + + --shadow: 0 2px 12px rgba(44, 36, 22, 0.08); + --shadow-hover: 0 8px 24px rgba(44, 36, 22, 0.15); + --shadow-modal: 0 20px 60px rgba(0, 0, 0, 0.3); + + --radius: 12px; + --radius-sm: 8px; + --radius-xs: 4px; + --alert-bg: #fff3cd; --alert-border: #ffc107; --alert-text: #856404; - --accent-dark: #a05c2c; - --border: #e8e0d4; - --shadow: 0 2px 12px rgba(44, 36, 22, 0.08); - --shadow-hover: 0 8px 24px rgba(44, 36, 22, 0.15); - --radius: 12px; - --radius-sm: 8px; + + /* ECharts 专用 */ + --chart-axis: #6b5d4f; + --chart-axis-line: #e8e0d4; + --chart-split-line: #f0ebe3; + --chart-label: #6b5d4f; + --chart-border-color: #fff; + --chart-tooltip-bg: rgba(255, 255, 255, 0.95); + --chart-tooltip-border: #e8e0d4; + --chart-tooltip-text: #2c2416; + --chart-review-bg: #fff8e1; + --chart-review-border: #ffc107; + --chart-highlight-bg: #f8f5f0; + + /* 导航栏 */ + --nav-bg: rgba(255, 255, 255, 0.92); + --nav-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); + + /* 模态遮罩 */ + --modal-overlay: rgba(0, 0, 0, 0.5); + + /* 主题切换按钮 */ + --toggle-bg: #f0ebe3; + --toggle-icon-sun: #f59e0b; + --toggle-icon-moon: #6b5d4f; + + /* 评分标签 */ + --rating-color: #e65100; + --rating-bg: #fff3e0; + --rating-star: #ff9800; + + /* 徽章 */ + --badge-finished-bg: #4caf50; + --badge-top-bg: rgba(255, 215, 0, 0.9); + --badge-top-text: #5d4037; + --rank-bg: rgba(0, 0, 0, 0.7); + --rank-text: #ffd700; } +[data-theme="dark"] { + /* 黑暗模式 - 暖色深调,保持文学质感 */ + --bg-primary: #1a1612; + --bg-card: #252019; + --bg-secondary: #2d2820; + --bg-hero: linear-gradient(135deg, #3d2e1a 0%, #5c3f1e 50%, #4a3015 100%); + --bg-hero-overlay: rgba(255, 255, 255, 0.03); + + --text-primary: #e8e0d4; + --text-secondary: #b0a698; + --text-light: #8a7f70; + + --accent: #d4925a; + --accent-light: #e8a87c; + --accent-dark: #b87436; + --accent-bg: rgba(212, 146, 90, 0.12); + --accent-bg-hover: rgba(212, 146, 90, 0.18); + + --border: #3a342c; + --border-light: #2d2820; + + --shadow: 0 2px 12px rgba(0, 0, 0, 0.3); + --shadow-hover: 0 8px 24px rgba(0, 0, 0, 0.4); + --shadow-modal: 0 20px 60px rgba(0, 0, 0, 0.6); + + --alert-bg: #3d2f15; + --alert-border: #8a6d1e; + --alert-text: #f0d77a; + + /* ECharts 专用 */ + --chart-axis: #b0a698; + --chart-axis-line: #3a342c; + --chart-split-line: #2d2820; + --chart-label: #b0a698; + --chart-border-color: #252019; + --chart-tooltip-bg: rgba(37, 32, 25, 0.95); + --chart-tooltip-border: #3a342c; + --chart-tooltip-text: #e8e0d4; + --chart-review-bg: #2d2515; + --chart-review-border: #66521e; + --chart-highlight-bg: #2d2820; + + /* 导航栏 */ + --nav-bg: rgba(26, 22, 18, 0.92); + --nav-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); + + /* 模态遮罩 */ + --modal-overlay: rgba(0, 0, 0, 0.7); + + /* 主题切换按钮 */ + --toggle-bg: #2d2820; + --toggle-icon-sun: #f59e0b; + --toggle-icon-moon: #d4925a; + + /* 评分标签 */ + --rating-color: #ff9800; + --rating-bg: #3d2e15; + --rating-star: #ffa726; + + /* 徽章 */ + --badge-finished-bg: #2e7d32; + --badge-top-bg: rgba(255, 215, 0, 0.85); + --badge-top-text: #3d2e15; + --rank-bg: rgba(0, 0, 0, 0.8); + --rank-text: #ffd700; +} + +/* ===== 全局过渡 ===== */ * { margin: 0; padding: 0; @@ -31,6 +150,18 @@ body { background: var(--bg-primary); color: var(--text-primary); line-height: 1.6; + transition: background-color 0.3s ease, color 0.3s ease; +} + +/* 所有主题相关元素平滑过渡 */ +.navbar, .nav-link, .stat-card, .chart-card, .top-book-card, .book-card, +.book-cover-wrapper, .notebook-card, .note-stat, .discover-card, .discover-tab, +.modal-content, .modal-overlay, .footer, .db-alert-banner, .page-btn, +.btn-primary, .btn-secondary, .search-input, .shelf-search, .highlight-item, +.review-item, .detail-progress-info, .top-book-cover-wrapper, +.theme-toggle, .loading-spinner { + transition: background-color 0.3s ease, border-color 0.3s ease, + color 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease; } .container { @@ -44,10 +175,11 @@ body { position: sticky; top: 0; z-index: 100; - background: rgba(255, 255, 255, 0.95); + background: var(--nav-bg); backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); + box-shadow: var(--nav-shadow); } .nav-container { @@ -76,6 +208,7 @@ body { .nav-links { display: flex; gap: 24px; + align-items: center; } .nav-link { @@ -90,12 +223,18 @@ body { .nav-link:hover { color: var(--accent); - background: rgba(193, 123, 74, 0.08); + background: var(--accent-bg); } .nav-link.active { color: var(--accent); - background: rgba(193, 123, 74, 0.12); + background: var(--accent-bg-hover); +} + +.nav-right { + display: flex; + align-items: center; + gap: 16px; } .nav-update { @@ -103,12 +242,42 @@ body { color: var(--text-light); } +/* ===== 主题切换按钮 ===== */ +.theme-toggle { + width: 40px; + height: 40px; + border: 1px solid var(--border); + border-radius: 50%; + background: var(--toggle-bg); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + line-height: 1; + color: var(--toggle-icon-moon); + flex-shrink: 0; +} + +.theme-toggle:hover { + border-color: var(--accent); + transform: scale(1.08); +} + +.theme-toggle .icon-sun { display: none; } +.theme-toggle .icon-moon { display: block; } + +[data-theme="dark"] .theme-toggle .icon-sun { display: block; } +[data-theme="dark"] .theme-toggle .icon-moon { display: none; } +[data-theme="dark"] .theme-toggle { color: var(--toggle-icon-sun); } + /* ===== Hero 区 ===== */ .hero-section { position: relative; padding: 80px 0 60px; overflow: hidden; background: var(--bg-hero); + transition: background 0.5s ease; } .hero-bg { @@ -184,7 +353,7 @@ body { border-radius: var(--radius); padding: 24px; box-shadow: var(--shadow); - transition: transform 0.2s, box-shadow 0.2s; + transition: transform 0.2s, box-shadow 0.3s, background-color 0.3s, border-color 0.3s; text-align: center; border: 1px solid var(--border); } @@ -264,12 +433,13 @@ body { /* ===== 读书排行 ===== */ .top-books-section { padding: 60px 0; - background: rgba(193, 123, 74, 0.04); + background: var(--accent-bg); + transition: background-color 0.3s ease; } .top-books-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 20px; } @@ -278,7 +448,7 @@ body { border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); - transition: transform 0.2s, box-shadow 0.2s; + transition: transform 0.2s, box-shadow 0.3s, background-color 0.3s, border-color 0.3s; border: 1px solid var(--border); cursor: pointer; } @@ -292,8 +462,8 @@ body { position: absolute; top: 8px; left: 8px; - background: rgba(0, 0, 0, 0.7); - color: #ffd700; + background: var(--rank-bg); + color: var(--rank-text); width: 28px; height: 28px; border-radius: 50%; @@ -305,14 +475,26 @@ body { z-index: 5; } -.top-book-cover { +.top-book-cover-wrapper { position: relative; width: 100%; - height: 200px; - object-fit: cover; + aspect-ratio: 3 / 4; + border-radius: var(--radius-sm) var(--radius-sm) 0 0; + overflow: hidden; background: var(--bg-primary); } +.top-book-cover { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s; +} + +.top-book-card:hover .top-book-cover { + transform: scale(1.05); +} + .top-book-info { padding: 14px 16px; } @@ -353,7 +535,7 @@ body { font-size: 11px; padding: 2px 8px; border-radius: 10px; - background: rgba(193, 123, 74, 0.12); + background: var(--accent-bg-hover); color: var(--accent-dark); } @@ -390,7 +572,7 @@ body { .shelf-search:focus { outline: none; border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(193, 123, 74, 0.15); + box-shadow: 0 0 0 3px var(--accent-bg); } .filter-checkbox { @@ -448,11 +630,11 @@ body { position: absolute; top: 6px; right: 6px; - background: #4caf50; + background: var(--badge-finished-bg); color: white; font-size: 10px; padding: 2px 6px; - border-radius: 4px; + border-radius: var(--radius-xs); font-weight: 600; } @@ -460,11 +642,11 @@ body { position: absolute; top: 6px; left: 6px; - background: rgba(255, 215, 0, 0.9); - color: #5d4037; + background: var(--badge-top-bg); + color: var(--badge-top-text); font-size: 10px; padding: 2px 6px; - border-radius: 4px; + border-radius: var(--radius-xs); font-weight: 600; } @@ -531,7 +713,8 @@ body { /* ===== 笔记区 ===== */ .notes-section { padding: 60px 0; - background: rgba(193, 123, 74, 0.04); + background: var(--accent-bg); + transition: background-color 0.3s ease; } .notes-summary { @@ -576,7 +759,7 @@ body { gap: 14px; box-shadow: var(--shadow); border: 1px solid var(--border); - transition: transform 0.2s, box-shadow 0.2s; + transition: transform 0.2s, box-shadow 0.3s, background-color 0.3s, border-color 0.3s; } .notebook-card:hover { @@ -811,12 +994,12 @@ body { .search-input:focus { outline: none; border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(193, 123, 74, 0.15); + box-shadow: 0 0 0 3px var(--accent-bg); } .discover-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 20px; } @@ -826,7 +1009,7 @@ body { overflow: hidden; box-shadow: var(--shadow); border: 1px solid var(--border); - transition: transform 0.2s, box-shadow 0.2s; + transition: transform 0.2s, box-shadow 0.3s, background-color 0.3s, border-color 0.3s; cursor: pointer; } @@ -837,7 +1020,7 @@ body { .discover-cover { width: 100%; - height: 180px; + aspect-ratio: 3 / 4; object-fit: cover; background: var(--bg-primary); } @@ -871,16 +1054,16 @@ body { .discover-rating { font-size: 13px; - color: #e65100; + color: var(--rating-color); font-weight: 600; } .discover-rating-label { font-size: 11px; padding: 2px 6px; - border-radius: 4px; - background: #fff3e0; - color: #e65100; + border-radius: var(--radius-xs); + background: var(--rating-bg); + color: var(--rating-color); } .discover-reading-count { @@ -892,9 +1075,9 @@ body { margin-top: 6px; font-size: 12px; color: var(--accent); - background: rgba(193, 123, 74, 0.08); + background: var(--accent-bg); padding: 4px 8px; - border-radius: 4px; + border-radius: var(--radius-xs); } .discover-category { @@ -911,7 +1094,7 @@ body { left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.5); + background: var(--modal-overlay); z-index: 1000; justify-content: center; align-items: flex-start; @@ -929,8 +1112,9 @@ body { max-width: 700px; width: 100%; position: relative; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + box-shadow: var(--shadow-modal); margin-bottom: 40px; + border: 1px solid var(--border); } .modal-close { @@ -997,7 +1181,7 @@ body { font-size: 12px; padding: 2px 10px; border-radius: 10px; - background: rgba(193, 123, 74, 0.1); + background: var(--accent-bg); color: var(--accent-dark); } @@ -1127,7 +1311,7 @@ body { .notes-detail-modal .highlight-item { padding: 10px 14px; - background: var(--bg-primary); + background: var(--chart-highlight-bg); border-radius: var(--radius-sm); margin-bottom: 8px; font-size: 14px; @@ -1144,13 +1328,13 @@ body { .notes-detail-modal .review-item { padding: 10px 14px; - background: #fff8e1; + background: var(--chart-review-bg); border-radius: var(--radius-sm); margin-bottom: 8px; font-size: 14px; color: var(--text-primary); line-height: 1.7; - border-left: 3px solid #ffc107; + border-left: 3px solid var(--chart-review-border); } .notes-detail-modal .review-meta { @@ -1160,7 +1344,7 @@ body { } .notes-detail-modal .review-star { - color: #ff9800; + color: var(--rating-star); } .notes-detail-modal .empty-state { @@ -1195,6 +1379,9 @@ body { gap: 12px; } .top-books-grid { - grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + } + .nav-update { + display: none; } } diff --git a/static/js/app.js b/static/js/app.js index 059fefe..3a360ab 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -2,7 +2,61 @@ const API_BASE = ""; +// ===== 主题管理 ===== + +/** + * 获取当前主题。 + * @returns {"light"|"dark"} + */ +function getCurrentTheme() { + return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light"; +} + +/** + * 切换明亮/黑暗主题。 + * 持久化到 localStorage,并触发图表重绘。 + */ +function toggleTheme() { + const newTheme = getCurrentTheme() === "dark" ? "light" : "dark"; + document.documentElement.setAttribute("data-theme", newTheme); + localStorage.setItem("theme", newTheme); + refreshChartsForTheme(); +} + +/** + * 从 CSS 变量读取当前主题的颜色值,供 ECharts 使用。 + */ +function getChartColors() { + const cs = getComputedStyle(document.documentElement); + return { + axis: cs.getPropertyValue("--chart-axis").trim(), + axisLine: cs.getPropertyValue("--chart-axis-line").trim(), + splitLine: cs.getPropertyValue("--chart-split-line").trim(), + label: cs.getPropertyValue("--chart-label").trim(), + borderColor: cs.getPropertyValue("--chart-border-color").trim(), + tooltipBg: cs.getPropertyValue("--chart-tooltip-bg").trim(), + tooltipBorder: cs.getPropertyValue("--chart-tooltip-border").trim(), + tooltipText: cs.getPropertyValue("--chart-tooltip-text").trim(), + accent: cs.getPropertyValue("--accent").trim(), + accentLight: cs.getPropertyValue("--accent-light").trim(), + accentDark: cs.getPropertyValue("--accent-dark").trim(), + }; +} + // ===== 工具函数 ===== + +/** + * 升级微信读书封面图 URL 到高清晰度版本。 + * 微信读书 CDN 的封面图通过文件名前缀区分分辨率: + * t6_ = 低清缩略图(~150px,Retina 屏模糊) + * t8_ = 高清版(~500px,适合 2x/3x 屏幕) + * 如果 URL 不含 t6_ 前缀或已是高清则原样返回。 + */ +function hdCover(url) { + if (!url) return ""; + return url.replace("/t6_", "/t8_"); +} + async function fetchAPI(path) { const resp = await fetch(API_BASE + path); if (!resp.ok) throw new Error(`API error: ${resp.status}`); @@ -15,6 +69,26 @@ function formatHours(seconds) { } // ===== 数据库健康检查 ===== + +// 存储所有 ECharts 实例,用于主题切换时重绘 +const chartInstances = {}; + +/** + * 主题切换后重绘所有 ECharts 图表。 + */ +function refreshChartsForTheme() { + Object.values(chartInstances).forEach((chart) => { + if (chart && !chart.isDisposed()) { + chart.dispose(); + } + }); + // 重新加载所有图表 + loadYearlyTrend(); + loadTimeDistribution(); + loadCategories(); + loadAuthors(); +} + /** * 页面加载时检查 MySQL 数据库连接状态。 * 如果连接失败,显示告警横幅并阻止后续数据加载。 @@ -170,14 +244,21 @@ async function loadOverview() { async function loadYearlyTrend() { try { const data = await fetchAPI("/api/yearly-trend"); - const chart = echarts.init(document.getElementById("chart-yearly")); + const el = document.getElementById("chart-yearly"); + if (chartInstances.yearly) chartInstances.yearly.dispose(); + const chart = echarts.init(el); + chartInstances.yearly = chart; + const c = getChartColors(); const years = data.map((d) => d.year); const hours = data.map((d) => d.hours); chart.setOption({ tooltip: { trigger: "axis", + backgroundColor: c.tooltipBg, + borderColor: c.tooltipBorder, + textStyle: { color: c.tooltipText }, formatter: (params) => { const p = params[0]; return `${p.name}年
阅读: ${p.value} 小时`; @@ -187,14 +268,15 @@ async function loadYearlyTrend() { xAxis: { type: "category", data: years, - axisLabel: { color: "#6b5d4f" }, - axisLine: { lineStyle: { color: "#e8e0d4" } }, + axisLabel: { color: c.axis }, + axisLine: { lineStyle: { color: c.axisLine } }, }, yAxis: { type: "value", name: "小时", - axisLabel: { color: "#6b5d4f" }, - splitLine: { lineStyle: { color: "#f0ebe3" } }, + nameTextStyle: { color: c.axis }, + axisLabel: { color: c.axis }, + splitLine: { lineStyle: { color: c.splitLine } }, }, series: [ { @@ -207,15 +289,15 @@ async function loadYearlyTrend() { type: "linear", x: 0, y: 0, x2: 0, y2: 1, colorStops: [ - { offset: 0, color: "#e8a87c" }, - { offset: 1, color: "#c17b4a" }, + { offset: 0, color: c.accentLight }, + { offset: 1, color: c.accent }, ], }, }, label: { show: true, position: "top", - color: "#6b5d4f", + color: c.label, fontSize: 12, formatter: "{c}h", }, @@ -232,14 +314,21 @@ async function loadYearlyTrend() { async function loadTimeDistribution() { try { const data = await fetchAPI("/api/time-distribution"); - const chart = echarts.init(document.getElementById("chart-hours")); + const el = document.getElementById("chart-hours"); + if (chartInstances.hours) chartInstances.hours.dispose(); + const chart = echarts.init(el); + chartInstances.hours = chart; + const c = getChartColors(); const hours = data.map((d) => `${d.hour}时`); const minutes = data.map((d) => d.duration_min); chart.setOption({ tooltip: { trigger: "axis", + backgroundColor: c.tooltipBg, + borderColor: c.tooltipBorder, + textStyle: { color: c.tooltipText }, formatter: (params) => { const p = params[0]; return `${p.name}
阅读: ${p.value} 分钟`; @@ -250,17 +339,18 @@ async function loadTimeDistribution() { type: "category", data: hours, axisLabel: { - color: "#6b5d4f", + color: c.axis, fontSize: 10, interval: 2, }, - axisLine: { lineStyle: { color: "#e8e0d4" } }, + axisLine: { lineStyle: { color: c.axisLine } }, }, yAxis: { type: "value", name: "分钟", - axisLabel: { color: "#6b5d4f" }, - splitLine: { lineStyle: { color: "#f0ebe3" } }, + nameTextStyle: { color: c.axis }, + axisLabel: { color: c.axis }, + splitLine: { lineStyle: { color: c.splitLine } }, }, series: [ { @@ -269,15 +359,15 @@ async function loadTimeDistribution() { smooth: true, symbol: "circle", symbolSize: 4, - lineStyle: { width: 2, color: "#c17b4a" }, - itemStyle: { color: "#c17b4a" }, + lineStyle: { width: 2, color: c.accent }, + itemStyle: { color: c.accent }, areaStyle: { color: { type: "linear", x: 0, y: 0, x2: 0, y2: 1, colorStops: [ - { offset: 0, color: "rgba(193,123,74,0.3)" }, - { offset: 1, color: "rgba(193,123,74,0.02)" }, + { offset: 0, color: c.accent + "4D" }, + { offset: 1, color: c.accent + "05" }, ], }, }, @@ -294,8 +384,12 @@ async function loadTimeDistribution() { async function loadCategories() { try { const data = await fetchAPI("/api/categories"); - const chart = echarts.init(document.getElementById("chart-categories")); + const el = document.getElementById("chart-categories"); + if (chartInstances.categories) chartInstances.categories.dispose(); + const chart = echarts.init(el); + chartInstances.categories = chart; + const c = getChartColors(); const items = data.slice(0, 8).map((d) => ({ name: d.category_title, value: d.reading_time, @@ -304,6 +398,9 @@ async function loadCategories() { chart.setOption({ tooltip: { trigger: "item", + backgroundColor: c.tooltipBg, + borderColor: c.tooltipBorder, + textStyle: { color: c.tooltipText }, formatter: (p) => { const hours = (p.value / 3600).toFixed(1); return `${p.name}
阅读: ${hours} 小时 (${p.percent}%)`; @@ -315,7 +412,7 @@ async function loadCategories() { right: 10, top: 20, bottom: 20, - textStyle: { color: "#6b5d4f", fontSize: 11 }, + textStyle: { color: c.label, fontSize: 11 }, }, series: [ { @@ -325,7 +422,7 @@ async function loadCategories() { avoidLabelOverlap: false, itemStyle: { borderRadius: 6, - borderColor: "#fff", + borderColor: c.borderColor, borderWidth: 2, }, label: { show: false }, @@ -334,6 +431,7 @@ async function loadCategories() { show: true, fontSize: 14, fontWeight: "bold", + color: c.tooltipText, }, }, data: items, @@ -354,8 +452,12 @@ async function loadCategories() { async function loadAuthors() { try { const data = await fetchAPI("/api/authors"); - const chart = echarts.init(document.getElementById("chart-authors")); + const el = document.getElementById("chart-authors"); + if (chartInstances.authors) chartInstances.authors.dispose(); + const chart = echarts.init(el); + chartInstances.authors = chart; + const c = getChartColors(); const top10 = data.slice(0, 10); const names = top10.map((d) => d.name); const counts = top10.map((d) => d.count); @@ -364,6 +466,9 @@ async function loadAuthors() { tooltip: { trigger: "axis", axisPointer: { type: "shadow" }, + backgroundColor: c.tooltipBg, + borderColor: c.tooltipBorder, + textStyle: { color: c.tooltipText }, formatter: (params) => { const p = params[0]; return `${p.name}
阅读: ${p.value} 本`; @@ -372,14 +477,14 @@ async function loadAuthors() { grid: { left: 100, right: 40, top: 20, bottom: 20 }, xAxis: { type: "value", - axisLabel: { color: "#6b5d4f" }, - splitLine: { lineStyle: { color: "#f0ebe3" } }, + axisLabel: { color: c.axis }, + splitLine: { lineStyle: { color: c.splitLine } }, }, yAxis: { type: "category", data: names.reverse(), - axisLabel: { color: "#6b5d4f", fontSize: 12 }, - axisLine: { lineStyle: { color: "#e8e0d4" } }, + axisLabel: { color: c.axis, fontSize: 12 }, + axisLine: { lineStyle: { color: c.axisLine } }, }, series: [ { @@ -392,15 +497,15 @@ async function loadAuthors() { type: "linear", x: 0, y: 0, x2: 1, y2: 0, colorStops: [ - { offset: 0, color: "#e8a87c" }, - { offset: 1, color: "#c17b4a" }, + { offset: 0, color: c.accentLight }, + { offset: 1, color: c.accent }, ], }, }, label: { show: true, position: "right", - color: "#6b5d4f", + color: c.label, fontSize: 12, formatter: "{c}本", }, @@ -426,10 +531,11 @@ async function loadTopBooks() { .join(""); return `
-
+
${i + 1} - ${book.title} + ${book.title}
${book.title}
@@ -474,8 +580,9 @@ async function loadShelf(page) { return `
- ${book.title} + ${book.title} ${badges.join("")}
${book.title}
@@ -571,8 +678,9 @@ async function loadNotebooks() { const progress = nb.reading_progress || 0; return `
- ${nb.title} + ${nb.title}
${nb.title}
${nb.author}
@@ -612,8 +720,8 @@ function openBook(bookId) { body.innerHTML = `
- ${data.title} + ${data.title}
${data.title}
${data.author || ''}${data.translator ? ' / 译: ' + data.translator : ''}
@@ -655,8 +763,8 @@ function openNotes(bookId, title, author, cover) { const body = document.getElementById("notesDetailBody"); body.innerHTML = `
- ${title} + ${title}
${title}
${author || ''}
@@ -669,8 +777,8 @@ function openNotes(bookId, title, author, cover) { .then((data) => { let html = `
- ${title} + ${title}
${title}
${author || ''}
@@ -828,8 +936,9 @@ function renderDiscoverGrid(grid, books, showReason) { return `
- ${book.title} + ${book.title}
${book.title}
${book.author || ''}
diff --git a/templates/index.html b/templates/index.html index 802823f..885064a 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6,6 +6,17 @@ 我的读书数据 + + @@ -30,7 +41,13 @@ 笔记 推荐
- +
@@ -171,7 +188,7 @@