diff --git a/src/components/Header.astro b/src/components/Header.astro
index 4baedd4..ab6b5cb 100644
--- a/src/components/Header.astro
+++ b/src/components/Header.astro
@@ -13,6 +13,7 @@ const nav = [
{ href: '/archives/', label: t('nav_posts', curLocale) },
{ href: '/gallery/', label: t('nav_gallery', curLocale) },
{ href: '/about/', label: t('nav_about', curLocale) },
+ { href: '/opensource/', label: t('nav_opensource', curLocale) },
];
const switchHref = localePath(path, curLocale === 'zh' ? 'en' : 'zh');
const switchLabel = curLocale === 'zh' ? 'EN' : '中';
diff --git a/src/components/PostList.astro b/src/components/PostList.astro
index e5a9158..65a2caf 100644
--- a/src/components/PostList.astro
+++ b/src/components/PostList.astro
@@ -41,7 +41,12 @@ const mmdd = (d: Date) =>
if (rows.length === 0) return null;
return (
-
{TRACK_LABEL[cat]}
+
{rows.map((post) => (
-
@@ -79,6 +84,7 @@ const mmdd = (d: Date) =>
color: var(--ink-3);
font-variant-numeric: tabular-nums;
}
+ .shelf-link { float: right; font-size: 12.5px; color: var(--accent); font-weight: 400; }
.track {
display: flex;
align-items: center;
diff --git a/src/components/geek/ProjectWall.astro b/src/components/geek/ProjectWall.astro
index af60f34..5212fbb 100644
--- a/src/components/geek/ProjectWall.astro
+++ b/src/components/geek/ProjectWall.astro
@@ -3,6 +3,11 @@
// 双源数据见 src/lib/projects.ts;语言色点用 linguist 常用色映射
import { loadProjects, type RepoCard } from '../../lib/projects';
+interface Props {
+ /** 展示上限:首页精选 6;/opensource 全量传大数 */
+ limit?: number;
+}
+const { limit = 6 } = Astro.props;
const LANG_COLORS: Record = {
Astro: '#ff5a03', TypeScript: '#3178c6', JavaScript: '#f1e05a',
Python: '#3572a5', Go: '#00add8', Rust: '#dea584', Shell: '#89e051',
@@ -11,7 +16,7 @@ const LANG_COLORS: Record = {
let projects: RepoCard[] = [];
try {
- projects = await loadProjects();
+ projects = (await loadProjects()).slice(0, limit);
} catch {
projects = []; // 兜底已在 lib 内处理,此处再守一层:空墙不破构建
}
diff --git a/src/components/pages/BooksPage.astro b/src/components/pages/BooksPage.astro
new file mode 100644
index 0000000..d58f3ca
--- /dev/null
+++ b/src/components/pages/BooksPage.astro
@@ -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`),
+};
+---
+
+
+
{L.shelf}{L.count(books.length)}
+ {years.map((year) => (
+
+ ))}
+
+
+
diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts
index 736f540..9406124 100644
--- a/src/i18n/ui.ts
+++ b/src/i18n/ui.ts
@@ -10,6 +10,7 @@ const dict = {
nav_posts: { zh: '文章', en: 'Posts' },
nav_gallery: { zh: '图库', en: 'Gallery' },
nav_about: { zh: '关于', en: 'About' },
+ nav_opensource: { zh: '开源', en: 'Open Source' },
search_label: { zh: '搜索', en: 'Search' },
search_placeholder: { zh: '搜索文章…(Esc 关闭)', en: 'Search posts… (Esc to close)' },
search_hint: { zh: '索引由 Pagefind 构建期生成 · 静态站零后端', en: 'Index built by Pagefind · zero-backend static site' },
diff --git a/src/pages/books.astro b/src/pages/books.astro
new file mode 100644
index 0000000..9785add
--- /dev/null
+++ b/src/pages/books.astro
@@ -0,0 +1,4 @@
+---
+import BooksPage from '../components/pages/BooksPage.astro';
+---
+
diff --git a/src/pages/en/books.astro b/src/pages/en/books.astro
new file mode 100644
index 0000000..400f784
--- /dev/null
+++ b/src/pages/en/books.astro
@@ -0,0 +1,4 @@
+---
+import BooksPage from '../../components/pages/BooksPage.astro';
+---
+
diff --git a/src/pages/en/opensource.astro b/src/pages/en/opensource.astro
new file mode 100644
index 0000000..0d8685f
--- /dev/null
+++ b/src/pages/en/opensource.astro
@@ -0,0 +1,20 @@
+---
+import ProjectWall from '../../components/geek/ProjectWall.astro';
+import Heatmap from '../../components/geek/Heatmap.astro';
+import BaseLayout from '../../layouts/BaseLayout.astro';
+import { t } from '../../i18n/ui';
+---
+
+ Open Source
+ This site is itself open source: git.wait4x.online/wait4x/blog — the Astro SSG, dual-writing workflow, and the full build & deploy pipeline live in the repo. Below are all my public repositories on self-hosted gitea and GitHub, plus contributions from the past year.
+
+
+
+
+
diff --git a/src/pages/opensource.astro b/src/pages/opensource.astro
new file mode 100644
index 0000000..0b9cc2b
--- /dev/null
+++ b/src/pages/opensource.astro
@@ -0,0 +1,21 @@
+---
+import ProjectWall from '../components/geek/ProjectWall.astro';
+import Heatmap from '../components/geek/Heatmap.astro';
+import BaseLayout from '../layouts/BaseLayout.astro';
+import { t } from '../i18n/ui';
+---
+
+ 开源Open Source
+ 本站本身即开源:git.wait4x.online/wait4x/blog —— Astro SSG、双写作流、构建发布全链皆在仓中。以下是我在自托管 gitea 与 GitHub 上的全部公开仓库,以及最近一年的贡献活动。
+
+
+
+
+