feat: enhance UI, refactor services, improve templates and tests

- Replace image_extractor with pdf_image_extractor service
- Enhance pi_client with expanded API capabilities
- Improve summarizer service with additional features
- Update admin routes with more endpoints
- Add login page template
- Enhance detail page with comprehensive layout
- Improve search and trends pages
- Update base template with additional elements
- Refactor tests for better coverage
- Add validate_summary script
- Update project configuration and dependencies
This commit is contained in:
2026-06-07 19:38:58 +08:00
parent 4a72c35452
commit 0d293422ac
32 changed files with 2003 additions and 586 deletions
+225 -65
View File
@@ -1,17 +1,27 @@
/* ── kami 风格参考:纸张质感、留白、墨蓝强调色 ─────────────────── */
:root {
--bg: #faf8f5;
--surface: #ffffff;
--ink: #1a1a2e;
--ink-light: #4a4a6a;
--accent: #2d5f8a;
--accent-hover: #1d4a6f;
--border: #e8e4df;
--shadow: rgba(0, 0, 0, 0.06);
/* 色 — Kami warm palette */
--bg: #f5f4ed; /* parchment */
--surface: #faf9f5; /* ivory */
--ink: #141413; /* near black */
--ink-light: #3d3d3a; /* dark warm */
--ink-sub: #504e49; /* olive subtext */
--ink-muted: #6b6a64; /* stone tertiary */
--accent: #1B365D; /* ink blue */
--accent-hover: #142d4a; /* ink blue deep */
--accent-bg: rgba(27, 54, 93, 0.06); /* brand whisper */
--border: #e8e6dc; /* warm border */
--border-soft: #e5e3d8; /* soft row separator */
--shadow: rgba(0, 0, 0, 0.05); /* whisper shadow */
--radius: 8px;
--font-body: "Noto Serif SC", "Georgia", serif;
--font-sans: "Inter", "Noto Sans SC", system-ui, sans-serif;
--max-width: 960px;
/* 字体 — Kami serif-first */
--font-body: "TsangerJinKai02", "Source Han Serif SC", "Noto Serif CJK SC", "Songti SC", "STSong", Georgia, serif;
--font-sans: var(--font-body); /* Kami: sans = serif */
--mono: "JetBrains Mono", "SF Mono", "Fira Code", Consolas, Monaco, monospace;
/* 布局 */
--max-width: 1080px;
}
*,
@@ -60,7 +70,7 @@ a:hover {
.nav-brand {
font-family: var(--font-body);
font-size: 1.2rem;
font-weight: 700;
font-weight: 500;
color: var(--ink);
}
@@ -96,7 +106,7 @@ a:hover {
.date-title {
font-family: var(--font-body);
font-size: 1.5rem;
font-weight: 700;
font-weight: 500;
}
.date-nav-btn {
@@ -156,7 +166,7 @@ a:hover {
.paper-card {
background: var(--surface);
border: 1px solid var(--border);
border: 0.5px solid var(--border);
border-radius: var(--radius);
padding: 20px 24px;
transition: box-shadow 0.2s;
@@ -175,7 +185,7 @@ a:hover {
.paper-title {
font-family: var(--font-body);
font-size: 1.1rem;
font-weight: 600;
font-weight: 500;
line-height: 1.5;
flex: 1;
}
@@ -190,6 +200,7 @@ a:hover {
font-size: 0.85rem;
color: var(--ink-light);
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.paper-one-line,
@@ -215,12 +226,14 @@ a:hover {
.tag {
display: inline-block;
padding: 2px 8px;
background: #eef3f8;
padding: 1px 5px;
background: #EEF2F7;
color: var(--accent);
border-radius: 3px;
border-radius: 2px;
font-size: 0.75rem;
font-weight: 500;
font-weight: 600;
letter-spacing: 0.4px;
text-transform: uppercase;
}
.paper-footer {
@@ -233,28 +246,28 @@ a:hover {
.summary-badge {
font-size: 0.8rem;
padding: 2px 8px;
border-radius: 3px;
border-radius: 2px;
}
.summary-none {
background: #f0f0f0;
color: #888;
background: var(--border);
color: var(--ink-muted);
}
.summary-pending {
background: #fff3e0;
color: #e67e22;
background: rgba(27, 54, 93, 0.06);
color: var(--ink-sub);
}
.summary-processing {
background: #e3f2fd;
color: #1976d2;
background: rgba(27, 54, 93, 0.10);
color: var(--accent);
}
.summary-done {
background: #e8f5e9;
color: #388e3c;
background: rgba(27, 54, 93, 0.08);
color: #3d6e3d;
}
.summary-failed,
.summary-permanent_failure {
background: #fce4ec;
color: #c62828;
background: rgba(140, 40, 40, 0.08);
color: #8c2828;
}
.btn-detail {
@@ -293,7 +306,7 @@ a:hover {
.detail-title {
font-family: var(--font-body);
font-size: 1.6rem;
font-weight: 700;
font-weight: 500;
line-height: 1.4;
margin-bottom: 12px;
}
@@ -352,7 +365,7 @@ a:hover {
.summary-section h2 {
font-family: var(--font-body);
font-size: 1.05rem;
font-weight: 600;
font-weight: 500;
margin-bottom: 8px;
color: var(--accent);
}
@@ -385,27 +398,27 @@ a:hover {
margin-bottom: 24px;
}
.summary-placeholder.processing {
background: #e3f2fd;
background: rgba(27, 54, 93, 0.06);
}
.summary-placeholder.failed {
background: #fce4ec;
background: rgba(140, 40, 40, 0.06);
}
.summary-placeholder.none {
background: #f5f5f5;
background: var(--border);
}
.error-detail {
font-size: 0.85rem;
color: #c62828;
color: #8c2828;
margin-top: 8px;
}
.quality-warning {
padding: 10px 16px;
background: #fff8e1;
border: 1px solid #ffe082;
background: rgba(27, 54, 93, 0.06);
border: 1px solid var(--border-soft);
border-radius: var(--radius);
font-size: 0.85rem;
color: #f57f17;
color: var(--ink-sub);
margin-bottom: 16px;
}
@@ -528,7 +541,7 @@ a:hover {
}
.sort-toggle a.active {
color: var(--accent);
font-weight: 600;
font-weight: 500;
}
.sort-toggle a:hover {
color: var(--accent);
@@ -541,7 +554,7 @@ a:hover {
/* ── Search Highlight ───────────────────────────────────────────── */
mark {
background: #fff3cd;
background: rgba(27, 54, 93, 0.10);
color: var(--ink);
padding: 1px 2px;
border-radius: 2px;
@@ -590,7 +603,7 @@ mark {
.page-heading {
font-family: var(--font-body);
font-size: 1.5rem;
font-weight: 700;
font-weight: 500;
margin-bottom: 20px;
}
@@ -656,44 +669,60 @@ mark {
color: var(--accent);
}
.btn-bookmark.active {
color: #f0a500;
color: var(--accent);
}
/* ── Reading Badge ──────────────────────────────────────────────── */
.reading-badge {
font-size: 0.75rem;
padding: 2px 6px;
border-radius: 3px;
border-radius: 2px;
}
.reading-unread {
background: #f0f0f0;
color: #888;
background: var(--border);
color: var(--ink-muted);
}
.reading-skimmed {
background: #e3f2fd;
color: #1976d2;
background: rgba(27, 54, 93, 0.08);
color: var(--accent);
}
.reading-read_summary {
background: #e8f5e9;
color: #388e3c;
background: rgba(27, 54, 93, 0.06);
color: #3d6e3d;
}
.reading-read_full {
background: #e8f5e9;
color: #2e7d32;
background: rgba(27, 54, 93, 0.10);
color: #3d6e3d;
font-weight: 500;
}
/* ── Responsive ─────────────────────────────────────────────────── */
@media (max-width: 640px) {
@media (max-width: 880px) {
.container {
padding: 20px 32px;
}
.charts-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.container {
padding: 16px;
}
.nav-bar {
padding: 10px 16px;
flex-wrap: wrap;
}
.nav-search-input {
width: 120px;
}
.nav-links {
gap: 12px;
margin-left: 0;
width: 100%;
justify-content: center;
}
.date-nav {
gap: 8px;
}
@@ -757,8 +786,9 @@ mark {
color: var(--accent);
white-space: nowrap;
padding: 2px 8px;
background: #eef3f8;
background: #EEF2F7;
border-radius: 4px;
font-variant-numeric: tabular-nums;
}
/* ── Similar Papers ────────────────────────────────────────────── */
@@ -770,7 +800,7 @@ mark {
.similar-papers h2 {
font-family: var(--font-body);
font-size: 1.1rem;
font-weight: 600;
font-weight: 500;
margin-bottom: 12px;
color: var(--accent);
}
@@ -800,7 +830,7 @@ mark {
.trends-page h1 {
font-family: var(--font-body);
font-size: 1.5rem;
font-weight: 700;
font-weight: 500;
margin-bottom: 24px;
}
.charts-grid {
@@ -818,7 +848,7 @@ mark {
.chart-card h2 {
font-family: var(--font-body);
font-size: 1rem;
font-weight: 600;
font-weight: 500;
margin-bottom: 12px;
color: var(--accent);
}
@@ -826,17 +856,12 @@ mark {
width: 100% !important;
max-height: 300px;
}
@media (max-width: 768px) {
.charts-grid {
grid-template-columns: 1fr;
}
}
/* ── Compare Page ──────────────────────────────────────────────── */
.compare-page h1 {
font-family: var(--font-body);
font-size: 1.5rem;
font-weight: 700;
font-weight: 500;
margin-bottom: 24px;
}
.compare-table-wrapper {
@@ -860,7 +885,7 @@ mark {
}
.compare-table th {
background: var(--bg);
font-weight: 600;
font-weight: 500;
color: var(--ink-light);
white-space: nowrap;
min-width: 100px;
@@ -887,7 +912,7 @@ mark {
.image-gallery h2 {
font-family: var(--font-body);
font-size: 1.05rem;
font-weight: 600;
font-weight: 500;
margin-bottom: 12px;
color: var(--accent);
}
@@ -913,3 +938,138 @@ mark {
color: var(--ink-light);
text-align: center;
}
/* ── 前置知识卡片 ── */
.prerequisites-list {
display: grid;
gap: 1rem;
}
.concept-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem 1.2rem;
}
.concept-card h3 {
margin: 0 0 0.4rem 0;
font-size: 1rem;
color: var(--accent);
}
.concept-card p {
margin: 0.3rem 0 0 0;
font-size: 0.92rem;
line-height: 1.6;
color: var(--ink);
}
.concept-why {
font-style: italic;
color: var(--ink-light) !important;
border-left: 3px solid var(--accent);
padding-left: 0.8rem;
margin-top: 0.5rem !important;
}
/* ── 核心创新点 ── */
.key-idea {
background: linear-gradient(135deg, var(--accent-bg), var(--surface));
border-left: 4px solid var(--accent);
padding: 1rem 1.2rem;
border-radius: 0 8px 8px 0;
margin: 1rem 0;
}
/* ── 可折叠详情 ── */
.summary-section details {
margin: 0.8rem 0;
}
.summary-section details summary {
cursor: pointer;
font-weight: 500;
color: var(--accent);
padding: 0.4rem 0;
user-select: none;
}
.summary-section details summary:hover {
text-decoration: underline;
}
.summary-section details[open] summary {
margin-bottom: 0.5rem;
}
/* ── 内联图片 ── */
.inline-figure {
margin: 1.2rem 0;
text-align: center;
}
.inline-figure img {
max-width: 100%;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
cursor: zoom-in;
transition: box-shadow 0.2s;
}
.inline-figure img:hover {
box-shadow: 0 4px 16px rgba(0,0,0,0.14);
}
.inline-figure figcaption {
margin-top: 0.4rem;
font-size: 0.85rem;
color: var(--ink-light);
}
/* ── 图片灯箱 ── */
.lightbox-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
background: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
cursor: zoom-out;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s, visibility 0.2s;
}
.lightbox-overlay.active {
opacity: 1;
visibility: visible;
}
.lightbox-overlay img {
max-width: 95vw;
max-height: 95vh;
object-fit: contain;
border-radius: 4px;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.4);
}
/* ── Benchmark 表格 ── */
.benchmarks-table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
font-size: 0.9rem;
}
.benchmarks-table th {
background: var(--bg);
font-weight: 500;
padding: 0.5rem 0.8rem;
text-align: left;
border-bottom: 2px solid var(--border);
}
.benchmarks-table td {
padding: 0.5rem 0.8rem;
border-bottom: 1px solid var(--border);
}
.benchmarks-table .improvement {
color: #3d6e3d;
font-weight: 500;
}
/* ── 研究动机 ── */
.motivation-block p {
margin-bottom: 0.8rem;
}
+11
View File
@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="6" fill="#1B365D"/>
<g fill="none" stroke="#f5f4ed" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M8 7h6a2 2 0 0 1 2 2v16l-1-1-2 1-2-1-2 1V9a1 1 0 0 1 1-1z"/>
<path d="M24 7h-6a2 2 0 0 0-2 2v16l1-1 2 1 2-1 2 1V9a1 1 0 0 0-1-1z"/>
<line x1="12" y1="12" x2="12" y2="12.01"/>
<line x1="12" y1="16" x2="12" y2="16.01"/>
<line x1="20" y1="12" x2="20" y2="12.01"/>
<line x1="20" y1="16" x2="20" y2="16.01"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 568 B