feat(pages): /books 书架与 /opensource 开源页——导航第四项(T2/T5)
- BooksPage:色脊排版卡(mood 竖脊+文楷书名+作者+三行截断策展语)
× 年份分组规整网格;zh/en 双路由;阅读轨标题旁「书架 →」入口
- /opensource:全量仓墙(ProjectWall 加 limit prop,首页精选 6 不变)
+ 热力图 + 本站开源叙事段;导航第四项「开源」(i18n nav_opensource)
- 五书 frontmatter 策展字段(含泥潭=刘楚昕)
验证: build 28 页 exit 0;books/opensource zh/en 五路由产物断言过;
五书卡与作者 grep 在案;E2E 30/30 PASS
Spec: 2026-10-25_add-terminal-books-admin
Co-authored-by: GLM-5.3
This commit is contained in:
1 parent
3bd8369eda
commit
90574edce7
9 files changed
+180
-2
No files matched your search
@@ -0,0 +1,116 @@
|
||||
---
|
||||
// 书评索引画廊(/books):色脊排版卡 × 年份分组规整网格
|
||||
// 预研方案 B:色脊天然安全(mood 深浅跨亮暗对比度风险回避),零 JS
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { t } from '../../i18n/ui';
|
||||
import type { Locale } from '../../lib/locale';
|
||||
|
||||
interface Props { locale?: Locale }
|
||||
const { locale = 'zh' } = Astro.props;
|
||||
|
||||
const books = (await getCollection('posts', ({ data }) => !data.draft && data.category === 'reading' && !data.tags.includes('hidden')))
|
||||
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
|
||||
|
||||
const years = [...new Set(books.map((b) => b.data.pubDate.getFullYear()))].sort((a, b) => b - a);
|
||||
const L = {
|
||||
shelf: locale === 'zh' ? '书架' : 'Books',
|
||||
count: (n: number) => (locale === 'zh' ? `${n} 本` : `${n} books`),
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout title={`${L.shelf} · wait4x`} description={locale === 'zh' ? '读过的书与一句策展' : 'Books read, one line each'}>
|
||||
<h1 class="page-title">{L.shelf}<span class="count mono">{L.count(books.length)}</span></h1>
|
||||
{years.map((year) => (
|
||||
<section class="year-group">
|
||||
<h2 class="y-label mono">{year}</h2>
|
||||
<ul class="shelf">
|
||||
{books.filter((b) => b.data.pubDate.getFullYear() === year).map((b) => (
|
||||
<li>
|
||||
<a
|
||||
class={`book ${locale === 'en' ? 'en' : ''}`}
|
||||
href={locale === 'en' ? `/en/archives/${b.id}/` : `/archives/${b.id}/`}
|
||||
style={`--mood:${b.data.mood ?? 'var(--ink-4)'}`}
|
||||
>
|
||||
<i class="spine" aria-hidden="true"></i>
|
||||
<div class="bk-body">
|
||||
<strong class="bk-title">{b.data.title}</strong>
|
||||
{b.data.bookAuthor && <span class="bk-author">{b.data.bookAuthor}</span>}
|
||||
{b.data.description && <span class="bk-desc">{b.data.description}</span>}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
))}
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.page-title {
|
||||
font-size: var(--text-h1);
|
||||
color: var(--ink-1);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
.count { font-size: 13px; color: var(--ink-3); }
|
||||
.year-group { margin-top: var(--space-5); }
|
||||
.y-label { font-size: 16px; color: var(--ink-3); margin-bottom: var(--space-3); }
|
||||
.shelf {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: var(--space-3);
|
||||
}
|
||||
/* 色脊卡:纸底 + mood 竖脊 + 文楷书名;hover 边框转 mood(.repo 同语言) */
|
||||
.book {
|
||||
display: flex;
|
||||
min-height: 120px;
|
||||
background: var(--paper);
|
||||
border: 1px solid var(--paper-line);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
|
||||
}
|
||||
.book:hover { border-color: var(--mood); transform: translateY(-2px); }
|
||||
.spine {
|
||||
flex: none;
|
||||
width: 10px;
|
||||
background: var(--mood);
|
||||
border-radius: 10px 0 0 10px;
|
||||
}
|
||||
.bk-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
min-width: 0;
|
||||
}
|
||||
.bk-title {
|
||||
font-family: var(--font-kai);
|
||||
font-size: 17px;
|
||||
color: var(--paper-ink);
|
||||
line-height: 1.35;
|
||||
}
|
||||
.en .bk-title { font-family: var(--font-serif); }
|
||||
.bk-author {
|
||||
font-size: 12.5px;
|
||||
color: var(--ink-3);
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
.bk-desc {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
color: var(--ink-2);
|
||||
font-family: var(--font-sans);
|
||||
line-height: 1.5;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user