--- // 年份分组 + 轨道分节的文章列表(首页与 /archives/ 共用) // 轨道标签单一事实源:content.config 的 POST_TRACKS,此处不另立词表 import type { CollectionEntry } from 'astro:content'; import { POST_TRACKS, type PostCategory } from '../content.config'; import { t } from '../i18n/ui'; interface Props { /** 调用方已完成 draft 过滤与 pubDate 倒序 */ posts: CollectionEntry<'posts'>[]; locale?: 'zh' | 'en'; /** slug → 译题(en 列表显示英文标题,视觉复核范围外观察) */ titleOverrides?: Record; } const { posts, locale = 'zh', titleOverrides } = Astro.props; // 轨道标签走字典(en 首页复用本组件时的双语位);zh 保持原词表语义 const TRACK_LABEL: Record = { reading: t('category_reading', locale), tech: t('category_tech', locale), photo: t('category_photo', locale), }; const hrefOf = (id: string) => (locale === 'en' ? `/en/archives/${id}/` : `/archives/${id}/`); const byYear = new Map[]>(); for (const post of posts) { const year = post.data.pubDate.getUTCFullYear(); const bucket = byYear.get(year); if (bucket) bucket.push(post); else byYear.set(year, [post]); } const mmdd = (d: Date) => `${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`; ---
{[...byYear.entries()].map(([year, list]) => (

{year}

{(Object.keys(POST_TRACKS) as PostCategory[]).map((cat) => { const rows = list.filter((post) => post.data.category === cat); if (rows.length === 0) return null; return (