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:
+225
-65
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 |
Reference in New Issue
Block a user