mirror of
https://github.com/KingHWJ/WeReadBoard.git
synced 2026-11-03 18:24:58 +08:00
style: 格式化 CSS、JS 和 HTML 代码
This commit is contained in:
1 parent
40b00a8b40
commit
69bfe3ce0e
9 files changed
+3393
-226
No files matched your search
@@ -146,7 +146,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
||||||
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||||
background: var(--bg-primary);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@@ -154,14 +154,34 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 所有主题相关元素平滑过渡 */
|
/* 所有主题相关元素平滑过渡 */
|
||||||
.navbar, .nav-link, .stat-card, .chart-card, .top-book-card, .book-card,
|
.navbar,
|
||||||
.book-cover-wrapper, .notebook-card, .note-stat, .discover-card, .discover-tab,
|
.nav-link,
|
||||||
.modal-content, .modal-overlay, .footer, .db-alert-banner, .page-btn,
|
.stat-card,
|
||||||
.btn-primary, .btn-secondary, .search-input, .shelf-search, .highlight-item,
|
.chart-card,
|
||||||
.review-item, .detail-progress-info, .top-book-cover-wrapper,
|
.top-book-card,
|
||||||
.theme-toggle, .loading-spinner {
|
.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,
|
transition: background-color 0.3s ease, border-color 0.3s ease,
|
||||||
color 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease;
|
color 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -264,12 +284,25 @@ body {
|
|||||||
transform: scale(1.08);
|
transform: scale(1.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-toggle .icon-sun { display: none; }
|
.theme-toggle .icon-sun {
|
||||||
.theme-toggle .icon-moon { display: block; }
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
|
.theme-toggle .icon-moon {
|
||||||
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
|
display: block;
|
||||||
[data-theme="dark"] .theme-toggle { color: var(--toggle-icon-sun); }
|
}
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== 顶部常驻搜索框 ===== */
|
/* ===== 顶部常驻搜索框 ===== */
|
||||||
.global-search-bar {
|
.global-search-bar {
|
||||||
@@ -382,7 +415,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-parent.active .shelf-cat-count {
|
.shelf-cat-parent.active .shelf-cat-count {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,8 +436,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; transform: translateY(-4px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub {
|
.shelf-cat-sub {
|
||||||
@@ -443,7 +483,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub.active .shelf-cat-count-sm {
|
.shelf-cat-sub.active .shelf-cat-count-sm {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,8 +657,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeInTab {
|
@keyframes fadeInTab {
|
||||||
from { opacity: 0; transform: translateY(8px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 读书排行(竖向列表) ===== */
|
/* ===== 读书排行(竖向列表) ===== */
|
||||||
@@ -1090,7 +1137,7 @@ body {
|
|||||||
color: var(--alert-text);
|
color: var(--alert-text);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
animation: slideDown 0.3s ease-out;
|
animation: slideDown 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,8 +1158,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideDown {
|
@keyframes slideDown {
|
||||||
from { transform: translateY(-100%); opacity: 0; }
|
from {
|
||||||
to { transform: translateY(0); opacity: 1; }
|
transform: translateY(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 加载动画 ===== */
|
/* ===== 加载动画 ===== */
|
||||||
@@ -1133,7 +1187,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 推荐发现区 ===== */
|
/* ===== 推荐发现区 ===== */
|
||||||
@@ -1756,7 +1812,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.thought-filter-btn.active .filter-count {
|
.thought-filter-btn.active .filter-count {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1964,78 +2020,100 @@ body {
|
|||||||
.nav-links {
|
.nav-links {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-title {
|
.hero-title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-stats {
|
.hero-stats {
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-stat-value {
|
.hero-stat-value {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.charts-grid {
|
.charts-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-card.large {
|
.chart-card.large {
|
||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.book-grid {
|
.book-grid {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-books-list {
|
.top-books-list {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-row {
|
.top-book-row {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-mini-cover {
|
.top-book-mini-cover {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-rank-num {
|
.top-book-rank-num {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-update {
|
.nav-update {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-wrapper {
|
.global-search-wrapper {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-toolbar {
|
.thoughts-toolbar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-controls {
|
.thoughts-controls {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-search-input {
|
.thoughts-search-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-sort-select {
|
.thoughts-sort-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-search {
|
.shelf-search {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-categories {
|
.shelf-categories {
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-parent {
|
.shelf-cat-parent {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub {
|
.shelf-cat-sub {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
padding: 3px 9px;
|
padding: 3px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-subs {
|
.shelf-cat-subs {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-top {
|
.back-to-top {
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
@@ -2043,13 +2121,16 @@ body {
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-page-header {
|
.thoughts-page-header {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-book-cover {
|
.thoughts-book-cover {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-book-title {
|
.thoughts-book-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,11 +476,13 @@ async function loadYearlyTrend() {
|
|||||||
barWidth: "50%",
|
barWidth: "50%",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
borderRadius: [8, 8, 0, 0],
|
borderRadius: [8, 8, 0, 0],
|
||||||
color: { type: "linear", x: 0, y: 0, x2: 0, y2: 1,
|
color: {
|
||||||
|
type: "linear", x: 0, y: 0, x2: 0, y2: 1,
|
||||||
colorStops: [
|
colorStops: [
|
||||||
{ offset: 0, color: c.accentLight },
|
{ offset: 0, color: c.accentLight },
|
||||||
{ offset: 1, color: c.accent },
|
{ offset: 1, color: c.accent },
|
||||||
] },
|
]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
label: { show: true, position: "top", color: c.label, fontSize: 12, formatter: "{c}h" },
|
label: { show: true, position: "top", color: c.label, fontSize: 12, formatter: "{c}h" },
|
||||||
}],
|
}],
|
||||||
@@ -538,11 +540,13 @@ async function loadTimeDistribution() {
|
|||||||
lineStyle: { width: 2, color: c.accent },
|
lineStyle: { width: 2, color: c.accent },
|
||||||
itemStyle: { color: c.accent },
|
itemStyle: { color: c.accent },
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: { type: "linear", x: 0, y: 0, x2: 0, y2: 1,
|
color: {
|
||||||
|
type: "linear", x: 0, y: 0, x2: 0, y2: 1,
|
||||||
colorStops: [
|
colorStops: [
|
||||||
{ offset: 0, color: c.accent + "4D" },
|
{ offset: 0, color: c.accent + "4D" },
|
||||||
{ offset: 1, color: c.accent + "05" },
|
{ offset: 1, color: c.accent + "05" },
|
||||||
] },
|
]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
@@ -650,11 +654,13 @@ async function loadAuthors() {
|
|||||||
barWidth: "50%",
|
barWidth: "50%",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
borderRadius: [0, 6, 6, 0],
|
borderRadius: [0, 6, 6, 0],
|
||||||
color: { type: "linear", x: 0, y: 0, x2: 1, y2: 0,
|
color: {
|
||||||
|
type: "linear", x: 0, y: 0, x2: 1, y2: 0,
|
||||||
colorStops: [
|
colorStops: [
|
||||||
{ offset: 0, color: c.accentLight },
|
{ offset: 0, color: c.accentLight },
|
||||||
{ offset: 1, color: c.accent },
|
{ offset: 1, color: c.accent },
|
||||||
] },
|
]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
label: { show: true, position: "right", color: c.label, fontSize: 12, formatter: "{c}本" },
|
label: { show: true, position: "right", color: c.label, fontSize: 12, formatter: "{c}本" },
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@@ -8,7 +9,7 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
|
||||||
<!-- 防闪烁:在 CSS 加载后、页面渲染前设置主题 -->
|
<!-- 防闪烁:在 CSS 加载后、页面渲染前设置主题 -->
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function () {
|
||||||
var saved = localStorage.getItem('theme');
|
var saved = localStorage.getItem('theme');
|
||||||
if (saved) {
|
if (saved) {
|
||||||
document.documentElement.setAttribute('data-theme', saved);
|
document.documentElement.setAttribute('data-theme', saved);
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- 数据库连接告警横幅(MySQL 连接失败时显示) -->
|
<!-- 数据库连接告警横幅(MySQL 连接失败时显示) -->
|
||||||
<div id="dbAlertBanner" class="db-alert-banner" style="display:none;">
|
<div id="dbAlertBanner" class="db-alert-banner" style="display:none;">
|
||||||
@@ -56,7 +58,8 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="global-search-wrapper">
|
<div class="global-search-wrapper">
|
||||||
<span class="global-search-icon">🔍</span>
|
<span class="global-search-icon">🔍</span>
|
||||||
<input type="text" id="globalSearchInput" class="global-search-input" placeholder="搜索图书..." onkeydown="if(event.key==='Enter')globalSearch()">
|
<input type="text" id="globalSearchInput" class="global-search-input" placeholder="搜索图书..."
|
||||||
|
onkeydown="if(event.key==='Enter')globalSearch()">
|
||||||
<button class="global-search-btn" onclick="globalSearch()">搜索</button>
|
<button class="global-search-btn" onclick="globalSearch()">搜索</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,7 +128,8 @@
|
|||||||
<label class="filter-checkbox">
|
<label class="filter-checkbox">
|
||||||
<input type="checkbox" id="finishedOnly"> 仅看已读完
|
<input type="checkbox" id="finishedOnly"> 仅看已读完
|
||||||
</label>
|
</label>
|
||||||
<button class="shelf-refresh-btn" id="shelfRefreshBtn" onclick="refreshShelf()" title="重新加载书架数据">
|
<button class="shelf-refresh-btn" id="shelfRefreshBtn" onclick="refreshShelf()"
|
||||||
|
title="重新加载书架数据">
|
||||||
<span class="btn-icon">⟳</span>
|
<span class="btn-icon">⟳</span>
|
||||||
<span class="btn-text">刷新</span>
|
<span class="btn-text">刷新</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -152,7 +156,8 @@
|
|||||||
<div class="container" style="padding-top:40px;padding-bottom:60px">
|
<div class="container" style="padding-top:40px;padding-bottom:60px">
|
||||||
<h2 class="section-title">🔍 推荐发现</h2>
|
<h2 class="section-title">🔍 推荐发现</h2>
|
||||||
<div class="discover-tabs">
|
<div class="discover-tabs">
|
||||||
<button class="discover-tab active" id="tabRecommend" onclick="switchDiscoverTab('recommend')">为你推荐</button>
|
<button class="discover-tab active" id="tabRecommend"
|
||||||
|
onclick="switchDiscoverTab('recommend')">为你推荐</button>
|
||||||
<button class="discover-tab" id="tabSearch" onclick="switchDiscoverTab('search')">搜索书籍</button>
|
<button class="discover-tab" id="tabSearch" onclick="switchDiscoverTab('search')">搜索书籍</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="recommendPanel" class="discover-panel">
|
<div id="recommendPanel" class="discover-panel">
|
||||||
@@ -164,7 +169,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="searchPanel" class="discover-panel" style="display:none">
|
<div id="searchPanel" class="discover-panel" style="display:none">
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<input type="text" id="searchInput" class="search-input" placeholder="输入书名、作者或关键词..." onkeydown="if(event.key==='Enter')doSearch()">
|
<input type="text" id="searchInput" class="search-input" placeholder="输入书名、作者或关键词..."
|
||||||
|
onkeydown="if(event.key==='Enter')doSearch()">
|
||||||
<button class="btn-primary" onclick="doSearch()">搜索</button>
|
<button class="btn-primary" onclick="doSearch()">搜索</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="discover-grid" id="searchGrid"></div>
|
<div class="discover-grid" id="searchGrid"></div>
|
||||||
@@ -183,7 +189,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container thoughts-content" id="thoughtsContent">
|
<div class="container thoughts-content" id="thoughtsContent">
|
||||||
<div class="loading"><div class="loading-spinner"></div></div>
|
<div class="loading">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -208,4 +216,5 @@
|
|||||||
|
|
||||||
<script src="/static/js/app.js"></script>
|
<script src="/static/js/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
+106
-24
@@ -146,7 +146,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
||||||
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||||
background: var(--bg-primary);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@@ -154,14 +154,34 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 所有主题相关元素平滑过渡 */
|
/* 所有主题相关元素平滑过渡 */
|
||||||
.navbar, .nav-link, .stat-card, .chart-card, .top-book-card, .book-card,
|
.navbar,
|
||||||
.book-cover-wrapper, .notebook-card, .note-stat, .discover-card, .discover-tab,
|
.nav-link,
|
||||||
.modal-content, .modal-overlay, .footer, .db-alert-banner, .page-btn,
|
.stat-card,
|
||||||
.btn-primary, .btn-secondary, .search-input, .shelf-search, .highlight-item,
|
.chart-card,
|
||||||
.review-item, .detail-progress-info, .top-book-cover-wrapper,
|
.top-book-card,
|
||||||
.theme-toggle, .loading-spinner {
|
.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,
|
transition: background-color 0.3s ease, border-color 0.3s ease,
|
||||||
color 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease;
|
color 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -264,12 +284,25 @@ body {
|
|||||||
transform: scale(1.08);
|
transform: scale(1.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-toggle .icon-sun { display: none; }
|
.theme-toggle .icon-sun {
|
||||||
.theme-toggle .icon-moon { display: block; }
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
|
.theme-toggle .icon-moon {
|
||||||
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
|
display: block;
|
||||||
[data-theme="dark"] .theme-toggle { color: var(--toggle-icon-sun); }
|
}
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== 顶部常驻搜索框 ===== */
|
/* ===== 顶部常驻搜索框 ===== */
|
||||||
.global-search-bar {
|
.global-search-bar {
|
||||||
@@ -382,7 +415,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-parent.active .shelf-cat-count {
|
.shelf-cat-parent.active .shelf-cat-count {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,8 +436,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; transform: translateY(-4px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub {
|
.shelf-cat-sub {
|
||||||
@@ -443,7 +483,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub.active .shelf-cat-count-sm {
|
.shelf-cat-sub.active .shelf-cat-count-sm {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,8 +657,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeInTab {
|
@keyframes fadeInTab {
|
||||||
from { opacity: 0; transform: translateY(8px); }
|
from {
|
||||||
to { opacity: 1; transform: translateY(0); }
|
opacity: 0;
|
||||||
|
transform: translateY(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 读书排行(竖向列表) ===== */
|
/* ===== 读书排行(竖向列表) ===== */
|
||||||
@@ -1101,7 +1148,7 @@ body {
|
|||||||
color: var(--alert-text);
|
color: var(--alert-text);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
animation: slideDown 0.3s ease-out;
|
animation: slideDown 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,8 +1169,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideDown {
|
@keyframes slideDown {
|
||||||
from { transform: translateY(-100%); opacity: 0; }
|
from {
|
||||||
to { transform: translateY(0); opacity: 1; }
|
transform: translateY(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 加载动画 ===== */
|
/* ===== 加载动画 ===== */
|
||||||
@@ -1144,7 +1198,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 推荐发现区 ===== */
|
/* ===== 推荐发现区 ===== */
|
||||||
@@ -1767,7 +1823,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.thought-filter-btn.active .filter-count {
|
.thought-filter-btn.active .filter-count {
|
||||||
background: rgba(255,255,255,0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1975,81 +2031,104 @@ body {
|
|||||||
.nav-links {
|
.nav-links {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-title {
|
.hero-title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-stats {
|
.hero-stats {
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-stat-value {
|
.hero-stat-value {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.charts-grid {
|
.charts-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-card.large {
|
.chart-card.large {
|
||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.book-grid {
|
.book-grid {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-books-list {
|
.top-books-list {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-row {
|
.top-book-row {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-mini-cover {
|
.top-book-mini-cover {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-book-rank-num {
|
.top-book-rank-num {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-update {
|
.nav-update {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-search-wrapper {
|
.global-search-wrapper {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-toolbar {
|
.thoughts-toolbar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-controls {
|
.thoughts-controls {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-search-input {
|
.thoughts-search-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-sort-select {
|
.thoughts-sort-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-search {
|
.shelf-search {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-filters {
|
.shelf-filters {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-categories {
|
.shelf-categories {
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-parent {
|
.shelf-cat-parent {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-sub {
|
.shelf-cat-sub {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
padding: 3px 9px;
|
padding: 3px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shelf-cat-subs {
|
.shelf-cat-subs {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-top {
|
.back-to-top {
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
@@ -2057,13 +2136,16 @@ body {
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-page-header {
|
.thoughts-page-header {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-book-cover {
|
.thoughts-book-cover {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts-book-title {
|
.thoughts-book-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
+2932
-98
File diff suppressed because it is too large.
Load diff
+6
-6
@@ -587,12 +587,12 @@ function renderNotes() {
|
|||||||
? statusBox('error', '暂时无法读取笔记', loadError.notes[noteBook] || '', 'retry-notes')
|
? statusBox('error', '暂时无法读取笔记', loadError.notes[noteBook] || '', 'retry-notes')
|
||||||
: statusBox('loading', '正在读取笔记内容…', '划线、想法与书签数量。'))
|
: statusBox('loading', '正在读取笔记内容…', '划线、想法与书签数量。'))
|
||||||
: `<div class="metrics-row"><span><strong>${counts.highlights + counts.thoughts + counts.bookmarks}</strong>条笔记</span><span>划线 ${counts.highlights}</span><span>想法 ${counts.thoughts}</span><span>书签 ${counts.bookmarks}</span></div>` +
|
: `<div class="metrics-row"><span><strong>${counts.highlights + counts.thoughts + counts.bookmarks}</strong>条笔记</span><span>划线 ${counts.highlights}</span><span>想法 ${counts.thoughts}</span><span>书签 ${counts.bookmarks}</span></div>` +
|
||||||
tabs([['all', '全部内容'], ['highlight', '划线'], ['thought', '想法 / 个人点评'], ['bookmark', '书签数量']], noteType, 'note-type') +
|
tabs([['all', '全部内容'], ['highlight', '划线'], ['thought', '想法 / 个人点评'], ['bookmark', '书签数量']], noteType, 'note-type') +
|
||||||
(noteType === 'bookmark'
|
(noteType === 'bookmark'
|
||||||
? `<div class="card empty">${counts.bookmarks} 个书签 · 微信读书接口只提供书签数量,不提供书签内容。</div>`
|
? `<div class="card empty">${counts.bookmarks} 个书签 · 微信读书接口只提供书签数量,不提供书签内容。</div>`
|
||||||
: (noteSlice.map(noteCard).join('') || '<div class="card empty">当前筛选没有笔记。</div>')) +
|
: (noteSlice.map(noteCard).join('') || '<div class="card empty">当前筛选没有笔记。</div>')) +
|
||||||
(noteType !== 'bookmark' && shownNotes.length > noteSlice.length ? `<button class="text-button section-space" data-action="notes-more">+ 继续加载(还有 ${shownNotes.length - noteSlice.length} 条)</button>` : '') +
|
(noteType !== 'bookmark' && shownNotes.length > noteSlice.length ? `<button class="text-button section-space" data-action="notes-more">+ 继续加载(还有 ${shownNotes.length - noteSlice.length} 条)</button>` : '') +
|
||||||
`<p class="hint section-space">${noteBook === 'all' ? `「全部笔记本」聚合了笔记最多的 ${payload.aggregated_books || 0} 本,切换左侧笔记本可查看单本全部内容。` : '内容来自微信读书划线与个人想法。'}总笔记数包含书签;导出包含划线和想法,不含公开点评及书签内容。</p>`;
|
`<p class="hint section-space">${noteBook === 'all' ? `「全部笔记本」聚合了笔记最多的 ${payload.aggregated_books || 0} 本,切换左侧笔记本可查看单本全部内容。` : '内容来自微信读书划线与个人想法。'}总笔记数包含书签;导出包含划线和想法,不含公开点评及书签内容。</p>`;
|
||||||
|
|
||||||
return welcome('把读过的,留在心里', `${notebooksData.totals.books} 本书留下过笔记,共 ${notebooksData.totals.notes} 条。`, '<button class="secondary" data-action="export-notes">↓ 导出当前书目笔记</button>') +
|
return welcome('把读过的,留在心里', `${notebooksData.totals.books} 本书留下过笔记,共 ${notebooksData.totals.notes} 条。`, '<button class="secondary" data-action="export-notes">↓ 导出当前书目笔记</button>') +
|
||||||
`<div class="notebook-grid"><aside class="card panel notebook-menu"><button data-action="notebook" data-id="all" class="${noteBook === 'all' ? 'active' : ''}"><b>全部笔记本</b><small>${notebooksData.totals.books} 本书 · ${notebooksData.totals.notes} 条笔记</small></button>${menuBooks.map(item => `<button data-action="notebook" data-id="${esc(item.id)}" class="${noteBook === item.id ? 'active' : ''}"><b>${esc(item.title)}</b><small>${item.total_notes} 条 · 含书签 ${item.bookmark_count}</small></button>`).join('')}</aside><div>${body}</div></div>`;
|
`<div class="notebook-grid"><aside class="card panel notebook-menu"><button data-action="notebook" data-id="all" class="${noteBook === 'all' ? 'active' : ''}"><b>全部笔记本</b><small>${notebooksData.totals.books} 本书 · ${notebooksData.totals.notes} 条笔记</small></button>${menuBooks.map(item => `<button data-action="notebook" data-id="${esc(item.id)}" class="${noteBook === item.id ? 'active' : ''}"><b>${esc(item.title)}</b><small>${item.total_notes} 条 · 含书签 ${item.bookmark_count}</small></button>`).join('')}</aside><div>${body}</div></div>`;
|
||||||
|
|||||||
+15
-15
@@ -1,25 +1,25 @@
|
|||||||
// 所有数据均为设计示例,不来自真实账号。
|
// 所有数据均为设计示例,不来自真实账号。
|
||||||
const books = [{title:'也许你该找个人聊聊',short:'也许你该\n找个人\n聊聊',author:'洛莉·戈特利布',en:'MAYBE YOU SHOULD TALK TO SOMEONE',cover:'c1',progress:68,status:'reading',score:'9.1',desc:'一位心理治疗师的回忆录。跟随几个普通人的故事,理解关系、失去与成长,也重新认识自己。'},{title:'三体',short:'三体',author:'刘慈欣',en:'THE THREE-BODY PROBLEM',cover:'c2',progress:42,status:'reading',score:'9.4',desc:'从一段隐秘的往事出发,走进人类与宇宙文明的宏大故事。科学、想象与命运交织,打开另一种观看世界的尺度。'},{title:'蛤蟆先生去看心理医生',short:'蛤蟆先生\n去看\n心理医生',author:'罗伯特·戴博德',en:'COUNSELLING FOR TOADS',cover:'c3',progress:85,status:'reading',score:'8.8',desc:'借由蛤蟆先生与心理咨询师的对话,探索情绪与行为背后的原因。这是一次关于理解自己、为自己负责的旅程。'},{title:'人生海海',short:'人生\n海海',author:'麦家',en:'LIFE IS A VAST SEA',cover:'c4',progress:26,status:'reading',score:'9.0',desc:'在复杂的时代与人情之中,讲述一个人的秘密与命运。人生如海,有暗流,也有让人继续前行的力量。'},{title:'活着',short:'活着',author:'余华',en:'TO LIVE',cover:'c3',progress:100,status:'done',score:'9.5',desc:'一个人与时代相遇的故事,关于生命的韧性与日常的重量。'},{title:'被讨厌的勇气',short:'被讨厌\n的勇气',author:'岸见一郎 / 古贺史健',en:'THE COURAGE TO BE DISLIKED',cover:'c1',progress:100,status:'done',score:'8.6',desc:'以对话的方式讨论人际关系、自我接纳与选择的自由。'},{title:'悉达多',short:'悉达多',author:'赫尔曼·黑塞',en:'SIDDHARTHA',cover:'c4',progress:0,status:'wish',score:'9.2',desc:'一个寻找自我的人,穿过不同的人生经验,在河流边学会倾听。'},{title:'置身事内',short:'置身\n事内',author:'兰小欢',en:'INSIDE THE SYSTEM',cover:'c2',progress:0,status:'wish',score:'9.3',desc:'从具体的经济生活出发,理解政府与经济发展的关系。'}];
|
const books = [{ title: '也许你该找个人聊聊', short: '也许你该\n找个人\n聊聊', author: '洛莉·戈特利布', en: 'MAYBE YOU SHOULD TALK TO SOMEONE', cover: 'c1', progress: 68, status: 'reading', score: '9.1', desc: '一位心理治疗师的回忆录。跟随几个普通人的故事,理解关系、失去与成长,也重新认识自己。' }, { title: '三体', short: '三体', author: '刘慈欣', en: 'THE THREE-BODY PROBLEM', cover: 'c2', progress: 42, status: 'reading', score: '9.4', desc: '从一段隐秘的往事出发,走进人类与宇宙文明的宏大故事。科学、想象与命运交织,打开另一种观看世界的尺度。' }, { title: '蛤蟆先生去看心理医生', short: '蛤蟆先生\n去看\n心理医生', author: '罗伯特·戴博德', en: 'COUNSELLING FOR TOADS', cover: 'c3', progress: 85, status: 'reading', score: '8.8', desc: '借由蛤蟆先生与心理咨询师的对话,探索情绪与行为背后的原因。这是一次关于理解自己、为自己负责的旅程。' }, { title: '人生海海', short: '人生\n海海', author: '麦家', en: 'LIFE IS A VAST SEA', cover: 'c4', progress: 26, status: 'reading', score: '9.0', desc: '在复杂的时代与人情之中,讲述一个人的秘密与命运。人生如海,有暗流,也有让人继续前行的力量。' }, { title: '活着', short: '活着', author: '余华', en: 'TO LIVE', cover: 'c3', progress: 100, status: 'done', score: '9.5', desc: '一个人与时代相遇的故事,关于生命的韧性与日常的重量。' }, { title: '被讨厌的勇气', short: '被讨厌\n的勇气', author: '岸见一郎 / 古贺史健', en: 'THE COURAGE TO BE DISLIKED', cover: 'c1', progress: 100, status: 'done', score: '8.6', desc: '以对话的方式讨论人际关系、自我接纳与选择的自由。' }, { title: '悉达多', short: '悉达多', author: '赫尔曼·黑塞', en: 'SIDDHARTHA', cover: 'c4', progress: 0, status: 'wish', score: '9.2', desc: '一个寻找自我的人,穿过不同的人生经验,在河流边学会倾听。' }, { title: '置身事内', short: '置身\n事内', author: '兰小欢', en: 'INSIDE THE SYSTEM', cover: 'c2', progress: 0, status: 'wish', score: '9.3', desc: '从具体的经济生活出发,理解政府与经济发展的关系。' }];
|
||||||
books.forEach((book, index) => { book.id = `b${index}`; });
|
books.forEach((book, index) => { book.id = `b${index}`; });
|
||||||
const booklists = [
|
const booklists = [
|
||||||
{id:'l1',name:'在故事里,读懂人生',source:'我的书单',description:'从别人的故事里,找到自己生活的回声。',ids:['b3','b4','b6']},
|
{ id: 'l1', name: '在故事里,读懂人生', source: '我的书单', description: '从别人的故事里,找到自己生活的回声。', ids: ['b3', 'b4', 'b6'] },
|
||||||
{id:'l2',name:'心理学,向内走一程',source:'我的书单',description:'理解情绪与关系,也练习温柔地对待自己。',ids:['b0','b2','b5']},
|
{ id: 'l2', name: '心理学,向内走一程', source: '我的书单', description: '理解情绪与关系,也练习温柔地对待自己。', ids: ['b0', 'b2', 'b5'] },
|
||||||
{id:'l3',name:'重新认识这个世界',source:'公开书单 · 示例',description:'从宇宙到日常,拓宽理解世界的尺度。',ids:['b1','b7','b6']},
|
{ id: 'l3', name: '重新认识这个世界', source: '公开书单 · 示例', description: '从宇宙到日常,拓宽理解世界的尺度。', ids: ['b1', 'b7', 'b6'] },
|
||||||
{id:'l4',name:'适合慢慢读的夜晚',source:'公开书单 · 示例',description:'把时间留给文学,让心绪落在书页之间。',ids:['b4','b6','b0']}
|
{ id: 'l4', name: '适合慢慢读的夜晚', source: '公开书单 · 示例', description: '把时间留给文学,让心绪落在书页之间。', ids: ['b4', 'b6', 'b0'] }
|
||||||
];
|
];
|
||||||
const initialGoals = [
|
const initialGoals = [
|
||||||
{id:'g1',name:'秋季文学计划',start:'2026-09-01',end:'2026-11-30',ids:['b3','b4','b6','b1'],sources:['在故事里,读懂人生']},
|
{ id: 'g1', name: '秋季文学计划', start: '2026-09-01', end: '2026-11-30', ids: ['b3', 'b4', 'b6', 'b1'], sources: ['在故事里,读懂人生'] },
|
||||||
{id:'g2',name:'给内心一点生长的空间',start:'2026-09-01',end:'2026-10-31',ids:['b0','b2','b5'],sources:['心理学,向内走一程']},
|
{ id: 'g2', name: '给内心一点生长的空间', start: '2026-09-01', end: '2026-10-31', ids: ['b0', 'b2', 'b5'], sources: ['心理学,向内走一程'] },
|
||||||
{id:'g3',name:'读完的书,成为自己的底气',start:'2026-08-01',end:'2026-08-31',ids:['b4','b5'],sources:[]}
|
{ id: 'g3', name: '读完的书,成为自己的底气', start: '2026-08-01', end: '2026-08-31', ids: ['b4', 'b5'], sources: [] }
|
||||||
];
|
];
|
||||||
const personalNotes = [
|
const personalNotes = [
|
||||||
{id:'n1',bookId:'b0',type:'thought',text:'把注意力还给生活本身,让平凡的日子有迹可循。',date:'2026-09-11'},
|
{ id: 'n1', bookId: 'b0', type: 'thought', text: '把注意力还给生活本身,让平凡的日子有迹可循。', date: '2026-09-11' },
|
||||||
{id:'n2',bookId:'b1',type:'highlight',text:'在辽阔的未知面前,每一个问题都值得被认真对待。',date:'2026-09-10'},
|
{ id: 'n2', bookId: 'b1', type: 'highlight', text: '在辽阔的未知面前,每一个问题都值得被认真对待。', date: '2026-09-10' },
|
||||||
{id:'n3',bookId:'b2',type:'thought',text:'允许情绪出现,也给自己一些理解它的时间。',date:'2026-09-08'},
|
{ id: 'n3', bookId: 'b2', type: 'thought', text: '允许情绪出现,也给自己一些理解它的时间。', date: '2026-09-08' },
|
||||||
{id:'n4',bookId:'b3',type:'highlight',text:'人生的答案,或许藏在继续向前的日子里。',date:'2026-09-06'}
|
{ id: 'n4', bookId: 'b3', type: 'highlight', text: '人生的答案,或许藏在继续向前的日子里。', date: '2026-09-06' }
|
||||||
];
|
];
|
||||||
const publicReviews = [
|
const publicReviews = [
|
||||||
{id:'r1',name:'山间来信',rating:5,type:'推荐',text:'适合放慢速度去读。最打动我的,是读完之后还会不断回想的那些问题。',date:'2026-09-10'},
|
{ id: 'r1', name: '山间来信', rating: 5, type: '推荐', text: '适合放慢速度去读。最打动我的,是读完之后还会不断回想的那些问题。', date: '2026-09-10' },
|
||||||
{id:'r2',name:'晚风书屋',rating:3,type:'一般',text:'有一些有趣的视角,也有需要耐心消化的地方。每个人会读出不同的感受。',date:'2026-09-09'},
|
{ id: 'r2', name: '晚风书屋', rating: 3, type: '一般', text: '有一些有趣的视角,也有需要耐心消化的地方。每个人会读出不同的感受。', date: '2026-09-09' },
|
||||||
{id:'r3',name:'一页一页',rating:1,type:'不行',text:'这次阅读没有找到共鸣,可能还不是适合我当下阅读的书。',date:'2026-09-08'}
|
{ id: 'r3', name: '一页一页', rating: 1, type: '不行', text: '这次阅读没有找到共鸣,可能还不是适合我当下阅读的书。', date: '2026-09-08' }
|
||||||
];
|
];
|
||||||
+160
-15
@@ -1,20 +1,165 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="zh-CN" data-theme="light">
|
<html lang="zh-CN" data-theme="light">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta charset="UTF-8">
|
||||||
<title>阅间 · 微信读书看板</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/static/css/styles.css">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<style>
|
<title>阅间 · 微信读书看板</title>
|
||||||
.footer{flex-wrap:wrap;gap:12px}.footer-meta{display:flex;align-items:center;gap:12px}.icp-link{color:inherit;text-decoration:none}.icp-link:hover{color:var(--accent)}
|
<link rel="stylesheet" href="/static/css/styles.css">
|
||||||
@media(max-width:600px){.footer-state{display:none}}
|
<style>
|
||||||
</style>
|
.footer {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none
|
||||||
|
}
|
||||||
|
|
||||||
|
.icp-link:hover {
|
||||||
|
color: var(--accent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width:600px) {
|
||||||
|
.footer-state {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<svg style="display:none" aria-hidden="true"><defs>
|
<svg style="display:none" aria-hidden="true">
|
||||||
<symbol id="book" viewBox="0 0 24 24"><path d="M3 4c4-1 6 0 9 2 3-2 5-3 9-2v15c-4-1-6 0-9 2-3-2-5-3-9-2zM12 6v15"/></symbol><symbol id="grid" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></symbol><symbol id="note" viewBox="0 0 24 24"><path d="M13 4H5v16h14v-8M11 13l1-4 7-7 3 3-7 7z"/></symbol><symbol id="search-icon" viewBox="0 0 24 24"><circle cx="10" cy="10" r="6.5"/><path d="m15 15 6 6"/></symbol><symbol id="chart" viewBox="0 0 24 24"><path d="M4 3v17h17M8 15v-4m5 4V7m5 8V4"/></symbol><symbol id="clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 6v6l4 2"/></symbol><symbol id="moon" viewBox="0 0 24 24"><path d="M20 14A9 9 0 0 1 10 3a9 9 0 1 0 10 11Z"/></symbol><symbol id="sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1"/></symbol><symbol id="sync" viewBox="0 0 24 24"><path d="M20 7v5h-5M4 17v-5h5M6 6a8 8 0 0 1 14 6M4 12a8 8 0 0 0 14 6"/></symbol><symbol id="flag" viewBox="0 0 24 24"><path d="M5 21V3c5-4 9 4 14 0v11c-5 4-9-4-14 0"/></symbol>
|
<defs>
|
||||||
</defs></svg>
|
<symbol id="book" viewBox="0 0 24 24">
|
||||||
<aside class="sidebar"><div class="logo"><div class="logo-mark"><svg><use href="#book"/></svg></div><div>阅间<small>READING SPACE</small></div></div><div class="navlabel">我的阅读空间</div><nav class="nav" aria-label="主导航"><button class="active" data-page="overview" title="阅读概览"><svg><use href="#grid"/></svg><span>阅读概览</span></button><button data-page="shelf" title="我的书架"><svg><use href="#book"/></svg><span>我的书架</span><em>8</em></button><button data-page="goals" title="阅读目标"><svg><use href="#flag"/></svg><span>阅读目标</span></button><button data-page="notes" title="笔记与划线"><svg><use href="#note"/></svg><span>笔记与划线</span></button><button data-page="discover" title="发现好书"><svg><use href="#search-icon"/></svg><span>发现好书</span></button></nav><div class="sidebar-bottom"><div class="connection"><span class="dot"></span>微信读书 · 个人空间<small>让每一页,都留下痕迹</small></div><div class="profile"><div class="avatar">读</div><div>我的阅读空间<small>数据来自你的微信读书账号</small></div></div></div></aside>
|
<path d="M3 4c4-1 6 0 9 2 3-2 5-3 9-2v15c-4-1-6 0-9 2-3-2-5-3-9-2zM12 6v15" />
|
||||||
<main class="main"><header class="topbar"><div class="breadcrumb">我的空间 <span>/ <b id="crumb" style="font-weight:400">阅读概览</b></span></div><div class="top-actions"><label class="searchbox"><svg><use href="#search-icon"/></svg><input id="global-search" placeholder="搜索书籍、书单…" aria-label="全局搜索"><span class="key">⌘ K</span></label><button class="iconbtn" id="theme" aria-label="切换至暗色主题"><svg><use href="#moon"/></svg></button><div class="avatar">L</div><form method="post" action="{{ url_for('auth.logout') }}"><input type="hidden" name="csrf_token" value="{{ csrf_token() }}"><button class="text-button logout-button" type="submit">退出</button></form></div></header><div class="demo-banner"><span><span class="dot"></span><span id="conn-state">正在连接微信读书…</span></span><span>阅读目标跨浏览器保存</span></div><div id="page-content"></div><footer class="footer"><span>阅间 · 与好书相伴,与自己相遇</span><div class="footer-meta"><span class="footer-state" id="footer-state">数据来自微信读书个人账号</span><a class="icp-link" href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">浙ICP备202607916号-1</a></div></footer></main>
|
</symbol>
|
||||||
<dialog id="detail" aria-label="内容详情"><div class="dialog-top"><h2 id="detail-title">书籍详情</h2><button class="iconbtn" data-action="close-detail" aria-label="关闭详情">✕</button></div><div id="detail-content"></div></dialog>
|
<symbol id="grid" viewBox="0 0 24 24">
|
||||||
<dialog id="goal-editor" aria-label="编辑阅读目标"><form id="goal-form"><div class="dialog-top"><div><div class="eyebrow">MAKE ROOM FOR READING</div><h2 id="editor-title">新建阅读目标</h2></div><button type="button" class="iconbtn" data-action="close-editor" aria-label="关闭目标编辑">✕</button></div><label class="field">目标名称<input id="goal-name" maxlength="60" placeholder="例如:秋季文学计划" required></label><div class="date-fields"><label class="field">开始日期<input id="goal-start" type="date" required></label><label class="field">结束日期<input id="goal-end" type="date" required></label></div><div class="section-head picker-head"><h3>想读些什么?</h3><span id="selection-count" class="pill"></span></div><p class="hint">选择书籍或加入书单当前书目,重复书籍只算一本,已读完直接计入完成。</p><label class="field"><input id="picker-search" placeholder="筛选书名、作者或书单…" aria-label="筛选目标书目"></label><div id="goal-picker"></div><p id="goal-error" class="form-error" role="alert"></p><div class="editor-footer"><span>保存后可在其他浏览器查看</span><button class="primary" type="submit">保存阅读目标</button></div></form></dialog>
|
<rect x="3" y="3" width="7" height="7" rx="1.5" />
|
||||||
<div id="toast" class="hidden" role="status"></div><script src="/static/js/weapi.js"></script><script src="/static/js/app.js"></script></body></html>
|
<rect x="14" y="3" width="7" height="7" rx="1.5" />
|
||||||
|
<rect x="3" y="14" width="7" height="7" rx="1.5" />
|
||||||
|
<rect x="14" y="14" width="7" height="7" rx="1.5" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="note" viewBox="0 0 24 24">
|
||||||
|
<path d="M13 4H5v16h14v-8M11 13l1-4 7-7 3 3-7 7z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="search-icon" viewBox="0 0 24 24">
|
||||||
|
<circle cx="10" cy="10" r="6.5" />
|
||||||
|
<path d="m15 15 6 6" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="chart" viewBox="0 0 24 24">
|
||||||
|
<path d="M4 3v17h17M8 15v-4m5 4V7m5 8V4" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="clock" viewBox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<path d="M12 6v6l4 2" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="moon" viewBox="0 0 24 24">
|
||||||
|
<path d="M20 14A9 9 0 0 1 10 3a9 9 0 1 0 10 11Z" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="sun" viewBox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="4" />
|
||||||
|
<path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1 1m12 12 1 1M5 19l1-1M18 6l1-1" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="sync" viewBox="0 0 24 24">
|
||||||
|
<path d="M20 7v5h-5M4 17v-5h5M6 6a8 8 0 0 1 14 6M4 12a8 8 0 0 0 14 6" />
|
||||||
|
</symbol>
|
||||||
|
<symbol id="flag" viewBox="0 0 24 24">
|
||||||
|
<path d="M5 21V3c5-4 9 4 14 0v11c-5 4-9-4-14 0" />
|
||||||
|
</symbol>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
<aside class="sidebar">
|
||||||
|
<div class="logo">
|
||||||
|
<div class="logo-mark"><svg>
|
||||||
|
<use href="#book" />
|
||||||
|
</svg></div>
|
||||||
|
<div>阅间<small>READING SPACE</small></div>
|
||||||
|
</div>
|
||||||
|
<div class="navlabel">我的阅读空间</div>
|
||||||
|
<nav class="nav" aria-label="主导航"><button class="active" data-page="overview" title="阅读概览"><svg>
|
||||||
|
<use href="#grid" />
|
||||||
|
</svg><span>阅读概览</span></button><button data-page="shelf" title="我的书架"><svg>
|
||||||
|
<use href="#book" />
|
||||||
|
</svg><span>我的书架</span><em>8</em></button><button data-page="goals" title="阅读目标"><svg>
|
||||||
|
<use href="#flag" />
|
||||||
|
</svg><span>阅读目标</span></button><button data-page="notes" title="笔记与划线"><svg>
|
||||||
|
<use href="#note" />
|
||||||
|
</svg><span>笔记与划线</span></button><button data-page="discover" title="发现好书"><svg>
|
||||||
|
<use href="#search-icon" />
|
||||||
|
</svg><span>发现好书</span></button></nav>
|
||||||
|
<div class="sidebar-bottom">
|
||||||
|
<div class="connection"><span class="dot"></span>微信读书 · 个人空间<small>让每一页,都留下痕迹</small></div>
|
||||||
|
<div class="profile">
|
||||||
|
<div class="avatar">读</div>
|
||||||
|
<div>我的阅读空间<small>数据来自你的微信读书账号</small></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
<main class="main">
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="breadcrumb">我的空间 <span>/ <b id="crumb" style="font-weight:400">阅读概览</b></span></div>
|
||||||
|
<div class="top-actions"><label class="searchbox"><svg>
|
||||||
|
<use href="#search-icon" />
|
||||||
|
</svg><input id="global-search" placeholder="搜索书籍、书单…" aria-label="全局搜索"><span class="key">⌘
|
||||||
|
K</span></label><button class="iconbtn" id="theme" aria-label="切换至暗色主题"><svg>
|
||||||
|
<use href="#moon" />
|
||||||
|
</svg></button>
|
||||||
|
<div class="avatar">L</div>
|
||||||
|
<form method="post" action="{{ url_for('auth.logout') }}"><input type="hidden" name="csrf_token"
|
||||||
|
value="{{ csrf_token() }}"><button class="text-button logout-button" type="submit">退出</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="demo-banner"><span><span class="dot"></span><span
|
||||||
|
id="conn-state">正在连接微信读书…</span></span><span>阅读目标跨浏览器保存</span></div>
|
||||||
|
<div id="page-content"></div>
|
||||||
|
<footer class="footer"><span>阅间 · 与好书相伴,与自己相遇</span>
|
||||||
|
<div class="footer-meta"><span class="footer-state" id="footer-state">数据来自微信读书个人账号</span><a class="icp-link"
|
||||||
|
href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer">浙ICP备202607916号-1</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</main>
|
||||||
|
<dialog id="detail" aria-label="内容详情">
|
||||||
|
<div class="dialog-top">
|
||||||
|
<h2 id="detail-title">书籍详情</h2><button class="iconbtn" data-action="close-detail"
|
||||||
|
aria-label="关闭详情">✕</button>
|
||||||
|
</div>
|
||||||
|
<div id="detail-content"></div>
|
||||||
|
</dialog>
|
||||||
|
<dialog id="goal-editor" aria-label="编辑阅读目标">
|
||||||
|
<form id="goal-form">
|
||||||
|
<div class="dialog-top">
|
||||||
|
<div>
|
||||||
|
<div class="eyebrow">MAKE ROOM FOR READING</div>
|
||||||
|
<h2 id="editor-title">新建阅读目标</h2>
|
||||||
|
</div><button type="button" class="iconbtn" data-action="close-editor" aria-label="关闭目标编辑">✕</button>
|
||||||
|
</div><label class="field">目标名称<input id="goal-name" maxlength="60" placeholder="例如:秋季文学计划"
|
||||||
|
required></label>
|
||||||
|
<div class="date-fields"><label class="field">开始日期<input id="goal-start" type="date" required></label><label
|
||||||
|
class="field">结束日期<input id="goal-end" type="date" required></label></div>
|
||||||
|
<div class="section-head picker-head">
|
||||||
|
<h3>想读些什么?</h3><span id="selection-count" class="pill"></span>
|
||||||
|
</div>
|
||||||
|
<p class="hint">选择书籍或加入书单当前书目,重复书籍只算一本,已读完直接计入完成。</p><label class="field"><input id="picker-search"
|
||||||
|
placeholder="筛选书名、作者或书单…" aria-label="筛选目标书目"></label>
|
||||||
|
<div id="goal-picker"></div>
|
||||||
|
<p id="goal-error" class="form-error" role="alert"></p>
|
||||||
|
<div class="editor-footer"><span>保存后可在其他浏览器查看</span><button class="primary" type="submit">保存阅读目标</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
<div id="toast" class="hidden" role="status"></div>
|
||||||
|
<script src="/static/js/weapi.js"></script>
|
||||||
|
<script src="/static/js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
+42
-32
@@ -1,39 +1,49 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="zh-CN" data-theme="light">
|
<html lang="zh-CN" data-theme="light">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>登录 · 阅间</title>
|
<title>登录 · 阅间</title>
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="login-page">
|
<body class="login-page">
|
||||||
<main class="login-shell">
|
<main class="login-shell">
|
||||||
<div class="logo login-logo"><div class="logo-mark"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4c4-1 6 0 8 2 2-2 4-3 8-2v15c-4-1-6 0-8 2-2-2-4-3-8-2zM12 6v15" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg></div><div>阅间<small>READING SPACE</small></div></div>
|
<div class="logo login-logo">
|
||||||
<section class="login-panel card">
|
<div class="logo-mark"><svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
<div class="eyebrow">YOUR READING SPACE</div>
|
<path d="M4 4c4-1 6 0 8 2 2-2 4-3 8-2v15c-4-1-6 0-8 2-2-2-4-3-8-2zM12 6v15" fill="none" stroke="currentColor"
|
||||||
<h1>{{ '服务暂不可用' if unavailable else ('首次设置' if not initialized else '欢迎回来') }}</h1>
|
stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
<p>{{ '请检查服务配置或数据库连接。' if unavailable else ('创建管理员账号以启用访问保护。' if not initialized else '登录后继续你的阅读旅程。') }}</p>
|
</svg></div>
|
||||||
{% if error %}<div class="login-error" role="alert">{{ error }}</div>{% endif %}
|
<div>阅间<small>READING SPACE</small></div>
|
||||||
{% if not unavailable and not initialized %}
|
</div>
|
||||||
{% if not setup_enabled %}<div class="login-error" role="alert">尚未配置一次性初始化口令,请联系管理员。</div>{% endif %}
|
<section class="login-panel card">
|
||||||
<form method="post" action="{{ url_for('auth.initialize_account') }}" class="login-form">
|
<div class="eyebrow">YOUR READING SPACE</div>
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<h1>{{ '服务暂不可用' if unavailable else ('首次设置' if not initialized else '欢迎回来') }}</h1>
|
||||||
<label>一次性初始化口令<input name="setup_token" type="password" autocomplete="off" required autofocus></label>
|
<p>{{ '请检查服务配置或数据库连接。' if unavailable else ('创建管理员账号以启用访问保护。' if not initialized else '登录后继续你的阅读旅程。') }}</p>
|
||||||
<label>管理员账号<input name="username" maxlength="64" autocomplete="username" required></label>
|
{% if error %}<div class="login-error" role="alert">{{ error }}</div>{% endif %}
|
||||||
<label>设置密码<input name="password" type="password" minlength="12" maxlength="256" autocomplete="new-password" required></label>
|
{% if not unavailable and not initialized %}
|
||||||
<button class="primary" type="submit" {% if not setup_enabled %}disabled{% endif %}>创建账号并进入</button>
|
{% if not setup_enabled %}<div class="login-error" role="alert">尚未配置一次性初始化口令,请联系管理员。</div>{% endif %}
|
||||||
</form>
|
<form method="post" action="{{ url_for('auth.initialize_account') }}" class="login-form">
|
||||||
{% elif not unavailable %}
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<form method="post" action="{{ url_for('auth.login') }}" class="login-form">
|
<label>一次性初始化口令<input name="setup_token" type="password" autocomplete="off" required autofocus></label>
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<label>管理员账号<input name="username" maxlength="64" autocomplete="username" required></label>
|
||||||
<label>账号<input name="username" maxlength="64" autocomplete="username" required autofocus></label>
|
<label>设置密码<input name="password" type="password" minlength="12" maxlength="256" autocomplete="new-password"
|
||||||
<label>密码<input name="password" type="password" autocomplete="current-password" required></label>
|
required></label>
|
||||||
<button class="primary" type="submit">登录</button>
|
<button class="primary" type="submit" {% if not setup_enabled %}disabled{% endif %}>创建账号并进入</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% elif not unavailable %}
|
||||||
</section>
|
<form method="post" action="{{ url_for('auth.login') }}" class="login-form">
|
||||||
<p class="login-foot">阅间 · 与好书相伴,与自己相遇</p>
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
</main>
|
<label>账号<input name="username" maxlength="64" autocomplete="username" required autofocus></label>
|
||||||
|
<label>密码<input name="password" type="password" autocomplete="current-password" required></label>
|
||||||
|
<button class="primary" type="submit">登录</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
<p class="login-foot">阅间 · 与好书相伴,与自己相遇</p>
|
||||||
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in new issue
Block a user