文章

Astro 内容站:SeriesSectionShelf 组件与系列目录页

把系列章节目录单独做成可复用的货架组件,让系列页只处理系列元数据,章节卡片渲染和排序结果直接落地。

系列内容和文章最大的差异,不在正文,而在“目录感”。

系列页不是一篇文章,它更像一个容器:上面是系列标题,下面是一整排章节入口。当前仓库里,这层专门抽成了:

  • src/components/series/SeriesSectionShelf.astro

为什么不直接在系列页里 map 章节

当然可以直接写,但这样会把两个职责重新混回一起:

  • SeriesDetailPageView 负责系列页整体结构
  • SeriesSectionShelf 负责章节货架的展示方式

一旦以后想改章节卡片样式、网格密度、badge 呈现,单独一个 shelf 组件会比在系列页里内联循环更稳。

组件输入已经是系列专用结构

SeriesSectionShelf 没有重复发明一套字段,而是直接吃 SeriesChapterCard[]

interface Props {
  chapterLabel: string;
  emptyLabel: string;
  items: SeriesChapterCard[];
  layout?: "stack" | "grid";
}

其中每个 SeriesChapterCard 在数据层里已经包含:

  • entry
  • href
  • badge

也就是说,章节排序、slug 推导、badge 生成,都在 lib/series.ts 里提前完成了。组件到手的已经是可直接渲染的结果。

Shelf 自己继续复用 ContentCardList

这个组件并没有另起一套卡片系统,而是在内部继续调用 ContentCardList。当前系列详情页会把它切到双列网格,而不是重新发明另一种卡片:

<ContentCardList
  layout="grid"
  emptyLabel={emptyLabel}
  items={items.map(({ badge, entry, href }) => ({
    href,
    eyebrow: `${chapterLabel} ${badge}`,
    title: entry.data.title,
    description: entry.data.description,
    meta: formatContentDate(entry.data.pubDate),
  }))}
/>

所以它的定位很明确:

  • 不是新的视觉体系
  • 而是“系列章节列表”的专用适配层

这样既保留了统一卡片语言,又让系列页拥有自己的字段语义。

系列页因此变得非常薄

SeriesDetailPageView.astro 现在只做这些事:

  1. 接收当前 series
  2. getFlatSeriesChapters(series, locale)
  3. 用分页逻辑切出当前页的 10 条章节
  4. 把系列标题、章节说明、章节 shelf 和分页导航组合起来

页面主体几乎就是:

<article class="series-page">
  <PageHero
    as="header"
    className="series-hero"
    backLink={{ href: getSeriesPath(), label: copy.series.backToSeries }}
    eyebrow={copy.series.heading}
    title={series.data.title}
  >
    <p class="series-meta">{chapterCountLabel}</p>
  </PageHero>

  <section class="page-section series-section">
    <PageSectionHeader
      title={copy.series.chapterListHeading}
      intro={copy.series.chapterListIntro}
    />
    <SeriesSectionShelf
      chapterLabel={copy.series.chapterLabel}
      emptyLabel={copy.series.chapterEmptyState}
      items={items}
      layout="grid"
    />
  </section>

  <PaginationNav ... />
</article>

这样系列页不会被章节渲染细节或头部模板拖重,页面文件保留了应有的清晰度。

badge 让章节目录更像目录,而不是普通文章列表

系列页和文章页最大的视觉差异,在当前实现里不是颜色,而是 badge。

SeriesChapterCard.badge 来自数据层:

  • 如果章节源 key 以数字开头,就显示补零后的序号
  • 否则退回到分类缩写

因此系列页天然更像一排带编号的章节入口,而不是一堆普通文章卡片。

为什么这个组件值得单独存在

因为它让“系列页”这件事被拆成了两半:

  • 系列页面负责系列层级
  • shelf 组件负责章节层级

这种拆法对系列站特别重要。系列一旦变多,系列页的稳定性比文章更依赖目录结构。把目录层单独做成组件,后面无论你增加系列封面、分卷、章节状态,都会更容易继续演化。

相关文章

Astro 内容站:PageHero 组件与页面头部统一

把列表页、首页、系列页和详情页里重复的标题区抽成 PageHero,让返回链接、eyebrow、标题和状态文案共用一套骨架。

2026-04-16

Astro 内容站:PageSectionHeader 组件与区块标题复用

把 section 标题、补充说明、右侧动作和分组计数统一到一个组件里,让首页、归档和索引列表共享稳定的区块头结构。

2026-04-16

Astro 内容站:组件组合重构、重复代码清理与文档同步

一次收口页面骨架、分页辅助、概览卡和旧文档漂移,把页面组合整理成更稳定的单组件文件结构。

2026-04-16

Astro 内容站:SummaryStatGrid 组件与归档总览卡

把归档页里重复的统计卡结构抽成 SummaryStatGrid,为总条目、文章数、章节数和最近更新时间提供统一的数值卡组件。

2026-04-16