这是本节的多页打印视图。 .

返回本页常规视图.

场景组件

使用本地内容与数据,配置完整的顺序阅读、版本发布、Landing 页面与 Book 出版流程。

场景组件解决的是一项完整的出版任务,而不是页面中的一个片段。每种场景都用一套严格契约,协同组织内容、本地数据、导航、运行时加载、无障碍与非 HTML 输出。

它与组件参考互为补充:查单个写作原语时看组件参考;当任务跨越多个页面、文件或输出格式时看本章。

选择场景

场景 适用任务 主要事实来源
顺序阅读 手册、Book 或博客需要可靠的阅读顺序 侧栏/内容树与页面元数据
版本发布与下载 发布事实、资产与安装路径必须保持一致 front matter 与 data/download/
Landing 页面 产品页面需要可复用的全宽分区 data/landing/ 或内联分区数据
Book 出版 长篇内容需要编号、引用与整本打印 既有 Book 内容树与稳定页面 ID

共同保证

  • 本地事实:正常构建不会通过远程 API 获取发布状态、star、价格、截图、头像或其他易变事实。
  • 静态优先:渐进增强前的 HTML 已包含完整内容;页面只加载自己确实使用的 JavaScript。
  • 严格输入:参数、标识符、URL、校验和或数据记录非法时,构建会在对应源码位置失败。
  • 感知输出:HTML、print、Markdown 与 RSS 要么得到明确的呈现,要么有意省略只用于交互的内容。
  • 单一导航事实源:可见内容树同时驱动翻页、Book 目录与整本打印顺序。
  • 多语言安全:共享事实按文档规定的后缀回退;叙事数据可以按语言独立维护。

采用之前

请固定拥有这些契约的最低版本:

GO
require github.com/pgsty/oink v0.4.1

使用 Hugo Extended 0.160.1 或更新版本。一次采用一种场景,构建所有已配置输出,并检查每种语言。本地构建、公开主题标签、站点版本固定与线上部署是不同的证据门禁,不要互相代替。

既有 Oink 站点请先阅读 0.4.0 升级指南

1 - 顺序阅读与数学公式

配置文档、Book 与博客共用的翻页体系,并使用本地服务端 KaTeX 渲染数学公式。

Oink 0.4.0 为手册、Book 与博客定义了明确的阅读序列,并把服务端数学公式渲染纳入正式内容路径。

启用或收窄翻页范围

docsbookblog 内容类型默认启用翻页。站点只使用其中一部分时,可以显式替换这个集合:

YAML
params:
  ui:
    pager:
      types: [docs, book, blog]

只允许这三个类型名。页面或分区可以使用布尔型 front matter 退出序列:

YAML
---
pager: false
---

交互式 HTML 只渲染实际存在的上一页或下一页,并在页面 <head> 中添加匹配的 <link rel="prev"><link rel="next">。print、Markdown 和 RSS 不包含翻页标记或关系。

理解阅读顺序

文档与 Book 按 侧栏同一导航根 做前序遍历:分区首页先于其可见子项,普通子项按 weight 排序。站点使用 data/docs_nav.json 显式定义内容树时,这棵树同时是侧栏与翻页的权威来源。

以下条目可以显示在导航中,但不会成为翻页目的地:

  • 使用 toc_hide 隐藏的页面;
  • 使用 manualLinkmanualLinkRelref 的纯链接占位页面;
  • 标记为 sidebar_divider: true 的不可点击分组行。

博客保留 Hugo 的分区时间顺序,刻意不沿用手册树顺序。

手册通常位于已配置的 docs 分区下。如果手册页面刻意放在内容根目录,而 /docs/ 只是概览页,请配置:

YAML
params:
  ui:
    sidebar_root_enabled: true
    docs_root: home

docs_root 只接受默认的 sectionhome,其他值会导致构建失败。选择 home 后,顶层 toc_root: true 概览分区仍不进入手册序列。

渲染分隔符公式

Hugo 不会把主题的 Goldmark 配置合并到消费站,因此站点必须自行启用 passthrough 分隔符:

YAML
markup:
  goldmark:
    extensions:
      passthrough:
        enable: true
        delimiters:
          block: [['\[', '\]'], ['$$', '$$']]
          inline: [['\(', '\)']]

Oink 提供 passthrough 渲染钩子与本地 KaTeX CSS。公式在服务端渲染为 KaTeX 与 MathML,且只有公式页面会收到样式表。单独设置 math: true 不会启用分隔符解析。

请构建一页同时包含行内与块级分隔符的内容,然后检查 HTML 中是否出现 MathML,而不是原样的 $$。长块级公式在屏幕上限制在正文列内滚动,在打印中保持静态。

使用块级公式兜底

暂时无法启用 Goldmark passthrough 时,可以使用无参数块级形式:

GO-HTML-TEMPLATE
{{</* eq */>}}E = mc^2{{</* /eq */>}}

这个形式刻意不带编号,也不会创建锚点、题注或 Book 注册项;Markdown 与 RSS 输出为普通 $$ 块。要创建可引用的编号公式,请采用 Book 公式形式,并添加带引号的 num

验证阅读体验

  1. 对比侧栏顺序、q/e 快捷键与可见翻页。
  2. 确认纯链接、分隔项与隐藏条目都被跳过。
  3. 在第一项、中间项与最后一项检查页面 head 关系。
  4. 从子路径构建,确认翻页链接仍位于当前 origin。
  5. 确认 print、Markdown 与 RSS 不含只用于交互的翻页标记。
  6. 在两种颜色模式与打印中检查公式页,并确认普通页面没有加载 KaTeX CSS。

全部阅读快捷键见键盘导航

2 - 版本发布与下载

在不调用远程 API 的前提下,让发布事实、归档链接、校验和以及滚动/固定版本下载渠道保持一致。

Oink 把不可变的发布事实与呈现方式分开。发布页面拥有版本与仓库身份,本地下载数据拥有分发渠道;卡片、列表、校验和表、文档页与 Landing 页面都从这些记录推导,不必在多个模板中重复复制 URL 与命令。

定义发布事实

在页面 front matter 中添加严格的 release Map:

YAML
release:
  product: Pig
  version: 1.7.0
  repo: pgsty/pig
  tag: v1.7.0
  date: 2026-08-14
  prev: v1.6.0
  checksums: SHA256SUMS

versionrepo 必填。省略 tag 时推导为 v{version};省略 date 时使用页面日期。可选的 productprevchecksums 用于补全记录。未知键、错误类型或不符合 owner/name 形式的仓库都会让构建失败。

简单的 GitHub 发布也可以使用精确标签 URL 简写:

YAML
release: https://github.com/pgsty/pig/releases/tag/v1.7.0

Oink 在本地推导仓库、发布、归档、diff、校验和与资产链接。构建时不调用 GitHub,也不会声称某个标签或资产已经远程存在。

渲染发布卡片

在需要显示事实摘要的位置放入无参数短代码:

GO-HTML-TEMPLATE
{{</* release-card */>}}

调用中不接受事实或任何参数,页面 front matter 是唯一权威来源。HTML 得到无需运行时的语义化链接卡片;print 与 RSS 得到静态链接列表;Markdown 得到普通 Markdown 链接。

建立发布索引

发布分区可以启用确定性排序:

YAML
---
title: 版本发布
layout: releases
release_group_by_product: true
release_products: [OINK, Pig]
---

页面先按规范化发布日期降序,再按有效 SemVer 优先级降序,最后对现实中的非 SemVer 标签使用确定性字典序兜底。默认生成一条全局时间序列。设置 release_group_by_product: true 后,每个入选页面都必须定义 productrelease_products 接受单个产品或数组,按产品字符串精确匹配,并在排序前过滤;非法过滤条件会让构建失败,而不是渲染一个看似合理的空页面。

发布校验和资产

release-assets 中写入严格的 sha*sum 行:

GO-HTML-TEMPLATE
{{</* release-assets group="auto" */>}}
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef  pig-1.7.0-linux-amd64.tar.gz
fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 *pig-1.7.0-darwin-arm64.tar.gz
{{</* /release-assets */>}}

也可以把校验和文件提交为页面资源或 Hugo 资产,并且只引用一个来源:

GO-HTML-TEMPLATE
{{</* release-assets src="release/SHA256SUMS" group="auto" */>}}

解析器会拒绝格式错误的行并报告行号,也会拒绝混用算法、算法与哈希长度不符、类似路径的文件名和含糊的多输入来源。HTML 会链接每项资产,并按需加载一个本地复制运行时;print 显示完整哈希但不含控件;Markdown 与 RSS 输出完整哈希表。

group="auto" 会按常见平台与架构名称分组。只有声明预期校验和算法时才使用 algo;只有资产基址不同于 release 事实推导出的 URL 时才使用 base

只定义一次下载渠道

创建 data/download/pig.yaml

YAML
version: 1.7.0
repo: pgsty/pig
published: true
channels:
  - id: script
    kind: rolling
    title: Install script
    title_zh: 安装脚本
    icon: fa-solid fa-bolt
    note: Tracks the rolling stable channel.
    note_zh: 跟随滚动稳定渠道。
    steps:
      - title: Install
        title_zh: 安装
        code: curl -fsSL https://repo.example.org/pig/install | bash
        lang: bash
  - id: source
    kind: pinned
    title: Source archive
    title_zh: 源码归档
    icon: fa-solid fa-code-branch
    url: https://github.com/pgsty/pig/archive/refs/tags/${tag}.tar.gz
    steps:
      - title: Clone the tag
        title_zh: 克隆标签
        code: git clone --branch ${tag} https://github.com/pgsty/pig.git
        lang: bash
  - id: assets
    kind: pinned
    title: Release assets
    title_zh: 发布资产
    icon: fa-solid fa-box-open
    checksums_src: release/pig-SHA256SUMS

记录需要直接提供字符串 version,或通过 params.version 提供版本,同时要有非空 channels 数组。每个渠道需要唯一且可作为锚点的 id、唯一一种 kindrollingpinned),以及本地化标题。

共享字段依次尝试精确语言后缀、主语言后缀与无后缀字段。例如中文可能依次解析 title_zh_cntitle_zhtitle。只有固定版本渠道的 urlsteps[].code 可以插值 ${version}${tag}。滚动渠道拒绝所有插值,避免稳定命令误装成固定版本命令。

渲染下载内容

使用一个位置参数引用数据键:

GO-HTML-TEMPLATE
{{</* download "pig" */>}}

HTML 输出渠道索引与静态优先的内容分区;代码步骤复用 Oink 增强代码渲染器,校验和渠道复用 Release Assets。print 展开同一份安全内容;Markdown 输出标题、源码围栏与完整哈希;RSS 省略该组件。

不可变发布尚不存在时设置 published: false。滚动渠道仍可使用;固定版本渠道显示不可点击的待发布状态,省略固定版本命令,并禁用资产链接与复制控件。只有标签与资产能够解析后才翻转该事实,不要在正文中粘贴猜测的链接。

Landing 页面可以通过 download 分区消费同一记录:

YAML
sections:
  - type: download
    data:
      title: 下载 Pig
      keys: [pig]

发布检查清单

  1. 从源码发布流程确认版本、标签、上一标签、仓库与日期。
  2. 每项校验和提交前都与实际发布产物核对。
  3. 构建 HTML、print 与 Markdown,并检查非 HTML 中是否保留完整哈希。
  4. 发布前测试 published: false;只有远程标签和资产存在后才测试并设置为 true
  5. 验证每种语言与子路径部署。
  6. 分别记录源码完成、主题标签发布、模块解析、消费站固定版本与线上可用性。

3 - Landing 页面

使用本地、多语言数据与 Oink 严格校验的分区注册表,组合可复用的全宽产品页面。

Landing 页面是使用全宽场景外壳的普通 Hugo 内容页。它保留站点顶部导航栏、命令面板与已配置页脚,同时移除文档侧栏和目录栏。内容仍然位于本地并由服务端渲染,不需要前端构建或远程事实 API。

首页继续使用 data/home/<lang>.yaml,但内部已经与普通 Landing 页面共用渲染器与分区契约。

创建 Landing 页面

创建普通内容文件,并指定本地数据键:

YAML
---
title: 定价
layout: landing
landing: pricing
outputs: [HTML, print, markdown]
---

把中英文叙事数据放在独立文件中:

TEXT
data/
└── landing/
    └── pricing/
        ├── en.yaml
        └── zh.yaml

非首页 Landing 按以下顺序解析数据:

  1. 直接写在页面 front matter 中的 sections
  2. data/landing/<key>/<精确语言>.yaml
  3. data/landing/<key>.yaml 中的精确语言记录;
  4. 英文或无后缀的本地记录。

叙事内容优先使用分语言文件。共享事实字段可以依次使用精确语言后缀、主语言后缀与无后缀回退;语言标签中的 - 会规范化为 _。例如先尝试 title_zh_cn,再尝试 title_zh,最后使用 title。不接受 camelCase 后缀别名。

组合分区

sections 中的每项可以是类型字符串或 Map。Map 可以设置 type、通过另一个 key 读取数据、提供稳定 id、使用 enabled: false 暂时关闭,或直接携带一次性 data

YAML
sections:
  - type: hero
    data:
      eyebrow: 本地优先的工程文档
      title: 只用 Hugo 发布产品页面
      lead: 服务端输出完整内容,只在确有需要时增强。
      actions:
        - { label: 阅读文档, url: /docs/, style: primary }
  - type: metrics
    key: project-facts
  - type: command-box
    data:
      title: 安装
      code: hugo mod get github.com/pgsty/[email protected]
      lang: bash
  - type: download
    data:
      title: 下载
      keys: [product]
  - cta

project-facts:
  title: 本地事实
  items:
    - { value: 21, label: 分区类型 }
    - { value: 0, label: 运行时事实请求 }

新内容使用带连字符的标准类型名;既有首页数据中的下划线会做兼容性规范化。未知类型会给出警告,而不是静默消失。站点可以有意使用自有 partial 作为逃生舱,但它属于本地模板契约,不是可移植 Landing 数据。

分区注册表

Oink 0.4.0 提供 21 种标准分区:

类型 适用内容
hero 核心信息、操作与跟随主题的图片
metrics 紧凑事实、数字、链接与计数增强
capabilities 交替的功能叙事与专用视觉面板
principles 编号产品原则或工作原则
cards 通用功能、价值、服务或路径集合
logo-wall 使用网格或纯 CSS 跑马灯展示工具与伙伴
gallery 截图或图标示例
testimonials 带可选署名的引语
contributors 人员、角色、头像与个人链接
faq 原生展开控件或静态平铺问题列表
markdown 自由文字
cta 最后一个操作或紧凑操作组
pricing 产品层级、价格、功能与操作按钮
pricing-compare 不同定价层级的功能对比矩阵
command-box 可复制的聚焦命令与可选说明
steps 带可选命令示例的有序流程
timeline 带日期的里程碑、路线图与发布历史
code-plate 展示面板中的 Chroma 代码或严格逐行数据
case-study 带指标、引语与来源的证据型案例
download 一项或多项经过校验的 data/download/ 记录
bar-chart 不使用图表 JS 的非负数值归一化比较

既有首页配置说明了共用集合与 Hero 字段。对 9 种面向场景的新类型,可以从小记录开始,让严格校验指出缺失或非法字段。Oink 仓库的 exampleSite 数据是完整的可执行参考。

保持事实本地化

价格、star、截图、头像、引语与下载状态必须在 Hugo 启动前就已存在。请在站点自己的维护任务或 CI 中刷新,审阅差异后再提交或生成本地数据。不要在分区中添加浏览器 fetch。

可选的本地外壳事实同样经过严格校验:

YAML
params:
  offlineSearch: true
  ui:
    landing_search: true
    github_stars: 2189
    alt_site:
      label: English site
      url: https://example.com/

landing_search 必须是布尔值,并且只有站点同时启用 offlineSearch 时才显示既有本地命令面板。github_stars 是已提交的字符串或数字,不会触发 GitHub API 请求。alt_site 要求标签与绝对 HTTP(S) URL。

渐进增强与无障碍

HTML 设置一个页面标记,并按需加载 landing.js。该运行时增强渐显、计数、复制、主题图片与紧凑菜单;关闭 JavaScript 后,服务端文档仍然完整。

跑马灯复制轨道只使用 CSS,副本不会暴露给辅助技术,也不可交互;本地化复选框无需 JavaScript 即可暂停。减少动态效果偏好会关闭移动与渐显过渡;强制颜色模式会保留控件与状态差异。紧凑菜单使用真实链接与按钮,不锁定焦点,也不会复制桌面导航树。

输出与验收

输出 契约
HTML 完整静态内容,再按需渐进增强
print 保留内容,动态区域变静态,移除控件
Markdown 标题、正文、列表、表格与代码,不含组件类名
RSS 省略 Landing 分区

发布前请分别检查关闭 JavaScript、减少动态效果、强制颜色、纯键盘输入、两种颜色模式、每种语言与子路径 base URL。确认所有站内链接与资产都保留部署前缀。既有 Docsy block 短代码仍兼容,但新页面应使用 Landing 数据,不要再增加一层自定义 HTML。

4 - Book 出版

使用同一棵导航树、编号组件、稳定交叉引用、生成式索引与整本打印 HTML 出版长篇内容。

Oink 的 Book 能力扩展现有文档外壳,沿用内容树或 data/docs_nav.json、面包屑导航、翻页与感知输出的组件体系,不会引入第二份章节清单或平行导航实现。

创建 Book 根页面

分区 Book 声明类型、请求所需输出,并把类型级联到后代:

YAML
---
title: 系统手册
type: book
book_kind: book
book_number: B
outputs: [HTML, print, markdown]
cascade:
  type: book
---

即使站点启用了侧栏根切换器,Book 根始终是当前一级分区,因此导航不会泄漏到同级文档或博客。站点覆盖 params.ui.shell_types 时,请保留 book

必须显式请求 print:Oink 不会擅自给消费站增加昂贵的聚合输出。分区 Book 对应 Hugo 的 section 输出类型;只有 Book 位于站点根时才使用 home

YAML
outputs:
  section: [HTML, print]
params:
  ui:
    shell_types: [docs, book, blog, swagger]
    sidebar_headings: 3
    book_draft_banner: true

sidebar_headings 接受 false、表示二级标题的 true,或 2 到 4 之间的最大标题层级;它会把当前页的 Hugo fragment 树投射到章节行下。所有需要引用的标题都应使用显式 ID:

MARKDOWN
## 同步复制 {#sec_replication_sync}

自动生成的标题 slug 适合普通导航,但不是持久引用 API。

描述章节

章节可以使用既有元数据命名空间:

YAML
---
title: 复制
book_kind: chapter
book_number: 3
book_part: II
book_status: draft
weight: 30
---

book_number 会显示在页面、侧栏与生成的 Book 目录标题旁。book_status: draft 只是可见的编辑状态,不会改变 Hugo 发布状态;设置 book_draft_banner: true 后,页面中还会出现本地化提示。

添加编号组件

figtbleq 的编号形式要求 带引号的 num,内容只能包含字母、数字、点或连字符。默认 ID 分别为 fig-<num>tbl-<num>eq-<num>;迁移既有公开锚点时应显式设置稳定 ID。

图片

GO-HTML-TEMPLATE
{{</* fig num="2-1" id="office_2003" src="/fig/office.png"
    caption="Word 2003 界面" alt="堆叠了多行工具栏的 Word 2003"
    width="960" height="640" */>}}

新图片始终应提供有意义的 alttitle 是用于迁移的 caption 别名,两者互斥。图片可以使用 src 或内部 Markdown 内容,但不能同时使用。URL、class token 与正整数图片尺寸均会校验。

表格

GO-HTML-TEMPLATE
{{</* tbl num="2-1" id="output-matrix" caption="不同输出面的行为。" */>}}
| 输出面 | 标签 | 锚点 |
| --- | --- | --- |
| HTML | 可见 | 稳定 |
| print | 可见 | 稳定 |
{{</* /tbl */>}}

该组件把标签、Markdown 表格、题注与锚点放在同一个语义化 figure 中,不会用标题伪装题注。

公式

GO-HTML-TEMPLATE
{{</* eq num="5.3" id="eq-capacity" caption="容量近似式。" */>}}
X \approx \frac{C}{R+Z}
{{</* /eq */>}}

公式内容直接交给本地服务端 KaTeX,即使站点没有启用 Goldmark passthrough 也能工作。无参数 eq 仍是无编号块级公式兜底,不能成为 xref 目标。

重复 ID,或同类组件用不同 ID 声明同一编号,都会导致构建失败。题注是纯文本;图片与表格的内部内容遵循当前页面 Markdown 策略。

安全地交叉引用

按类型与编号引用目标:

GO-HTML-TEMPLATE
参见 {{</* xref fig="2-1" anchor="office_2003" */>}}

使用显式链接文字引用另一页标题:

GO-HTML-TEMPLATE
参见{{</* xref page="../replication" anchor="sec_replication_sync" */>}}同步复制{{</* /xref */>}}

xref 最多接受一种类型键(figtbleq),以及可选的 pageanchor。类型会提供本地化默认标签,并能推导默认锚点;只提供锚点时必须写内部链接文字。跨页查找使用 Hugo 当前语言的页面解析,因此源码无需硬编码 /en/ 路径。

引用与源码顺序无关,可以出现在目标之前。在整本 print 中,Book-aware xref 会变为文档内片段。普通 Markdown 跨页链接刻意保留为站点 URL,因此必须在聚合输出中工作的引用应使用 xref

生成 Book 索引

从同一棵有序 Book 树生成目录:

GO-HTML-TEMPLATE
{{</* book-toc depth=3 */>}}

深度 1 列章节,深度 2 加入嵌套分区,深度 3 再加入每页标题树。drafts=false 只会从该生成列表中过滤可见编辑草稿,不会取消页面发布。

生成图片、表格或公式清单:

GO-HTML-TEMPLATE
{{</* book-figures */>}}
{{</* book-figures kind="tbl" */>}}
{{</* book-figures kind="eq" */>}}

这些短代码会以确定方式触发并聚合后代内容,然后链接到稳定目标 ID,不需要复制一份注册表文件。

出版整本打印输出

Book 根的 print 输出依次生成封面、本地目录、根内容与阅读顺序中的可见后代。标记为 no_print: true 的页面、纯链接节点、侧栏分隔项与隐藏占位项都不会成为章节。

编号目标 ID 保持逐字节稳定。聚合文档会给页面局部 Markdown 标题 ID 添加来源页面前缀,因此 summary 之类重复锚点仍然唯一;生成的标题链接也会同步改写。Book 目录、图表清单与 xref 目标都会变为文档内地址。

产物是面向打印的 HTML,而不是依赖网络的 PDF/EPUB 流水线。分页、PDF 转换与 EPUB 打包仍由站点负责。

迁移既有书籍

先盘点,只转换无歧义形式;遇到缺失编号、题注、替代文字或目标时停止,不要猜测。公开 ID 与显示编号应分别保留。在分支上执行迁移,保存机器可读的前后报告,逐项审阅跳过记录,并要求第二次运行零变更。

Oink v0.4.0 源码提供先 dry-run、可幂等重跑的迁移工具,以及针对实测内容形态的 TPMEDDIApg-internal 方案。它们是对应源格式的可执行模式,不是通用题注猜测器。

验收 Book

  1. 对比侧栏、翻页、生成目录与整本打印的章节顺序。
  2. 确认每个编号目标 ID 唯一,并且每种语言下的 xref 都能到达类型和编号匹配的目标。
  3. 确认编号图片替代文字有意义,并与题注意图一致。
  4. 检查独立 HTML、Markdown、print 与整本聚合输出。
  5. 在聚合打印中测试重复标题名与跨章节引用。
  6. 从主题 checkout 工作时运行 scripts/check-book.py;消费站 CI 则应实现等价的渲染锚点检查。