From ed93785c10873beae795f11b3081040eb91f7d41 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Thu, 2 Jul 2026 12:32:17 +0800 Subject: [PATCH] Add page layout contract docs --- .../server/template-for-theme.md | 23 +++++ docs/developer-guide/theme/api-changelog.md | 6 ++ docs/developer-guide/theme/code-snippets.md | 6 +- docs/developer-guide/theme/page-layout.md | 87 +++++++++++++++++++ docs/developer-guide/theme/structure.md | 8 +- sidebars.js | 1 + 6 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 docs/developer-guide/theme/page-layout.md diff --git a/docs/developer-guide/plugin/api-reference/server/template-for-theme.md b/docs/developer-guide/plugin/api-reference/server/template-for-theme.md index fed27911..d6a1af88 100644 --- a/docs/developer-guide/plugin/api-reference/server/template-for-theme.md +++ b/docs/developer-guide/plugin/api-reference/server/template-for-theme.md @@ -44,6 +44,29 @@ public class MomentRouter { 使用 `TemplateNameResolver` 来解析模板名称,如果主题提供了对应的模板,那么就使用主题提供的模板,否则使用插件提供的模板,如果直接返回模板名称,那么只会使用主题提供的模板,如果主题没有提供对应的模板,那么会抛出异常。 +## 复用当前主题页面布局 + +从 Halo 2.26.0 开始,如果插件提供的前台页面希望复用当前主题的页头、页脚和整体页面外壳,可以在插件模板中调用 `layout :: html(...)`: + +```html title="src/main/resources/templates/moment.html" + + + + 瞬间 - [[${site.title}]] + + +
+ +
+
+ +``` + +`layout` 是 Halo 保留的集成模板名。当当前主题提供符合契约的 `templates/layout.html` 时,插件页面会使用主题布局;否则会使用 Halo 内置的 fallback 布局。完整契约可参考[页面布局契约](../../../theme/page-layout.md)。 + ## 模板片段 如果你的默认模板不止一个,你可能需要通过模板片段来抽取一些公共的部分,例如,你的插件提供了一个 `moment.html` 模板,你可能需要抽取一些公共的部分,例如头部、尾部等,你可以这样做: diff --git a/docs/developer-guide/theme/api-changelog.md b/docs/developer-guide/theme/api-changelog.md index dda9589c..2da8a277 100644 --- a/docs/developer-guide/theme/api-changelog.md +++ b/docs/developer-guide/theme/api-changelog.md @@ -3,6 +3,12 @@ title: API 变更日志 description: 记录每一个版本的主题 API 变更记录,方便开发者适配 --- +## 2.26.0 + +### 主题目录结构 > 新增页面布局契约 + +在 2.26.0 中,主题可以通过 `templates/layout.html` 提供 `html(head, content)` 片段,让插件前台页面复用当前主题的页面外壳。Halo 会在主题安装、更新或重载后检查这个模板,并通过 `Theme.status.pageLayout` 暴露 `SUPPORTED`、`MISSING` 或 `INVALID` 状态;未适配或校验异常时,使用布局契约的插件页面会回退到 Halo 内置布局。详细文档可查阅:[页面布局契约](../../developer-guide/theme/page-layout.md)。 + ## 2.25.0 ### 表单定义 > `select` 选项支持图标和描述 diff --git a/docs/developer-guide/theme/code-snippets.md b/docs/developer-guide/theme/code-snippets.md index 632936c3..0496057e 100644 --- a/docs/developer-guide/theme/code-snippets.md +++ b/docs/developer-guide/theme/code-snippets.md @@ -5,7 +5,7 @@ description: 本文档介绍了常用的代码片段,以便于开发者快速 ## 布局模板 -通常情况下,我们需要一个公共模板来定义页面的布局。 +通常情况下,我们需要一个公共模板来定义页面的布局。从 Halo 2.26.0 开始,如果主题在 `templates/layout.html` 中声明 `html(head, content)` 片段,这个模板也会被识别为[页面布局契约](./page-layout.md),用于让插件前台页面复用当前主题的页面外壳。 ```html title="templates/layout.html" @@ -33,7 +33,7 @@ description: 本文档介绍了常用的代码片段,以便于开发者快速 @@ -45,3 +45,5 @@ description: 本文档介绍了常用的代码片段,以便于开发者快速 ``` + +如果只是主题内部私有布局,也可以放在 `templates/modules/layout.html` 等其他路径中,再通过 `modules/layout :: ...` 引用。 diff --git a/docs/developer-guide/theme/page-layout.md b/docs/developer-guide/theme/page-layout.md new file mode 100644 index 00000000..322ceb29 --- /dev/null +++ b/docs/developer-guide/theme/page-layout.md @@ -0,0 +1,87 @@ +--- +title: 页面布局契约 +description: 了解如何通过主题提供页面布局,让插件前台页面复用当前主题的页面外壳。 +--- + +从 Halo 2.26.0 开始,主题可以通过 `templates/layout.html` 提供一个标准页面布局契约。插件提供的前台页面调用这个契约后,可以复用当前主题的页头、页脚、样式和响应式布局;如果当前主题没有适配,Halo 会使用内置的 fallback 布局保证页面可以继续渲染。 + +这个能力是增量适配项,不会影响主题安装、升级、启用,也不会替代主题内部自用的普通模板片段。 + +## 适配主题布局 + +主题需要在 `templates/layout.html` 中声明 `html(head, content)` 片段: + +```html title="templates/layout.html" + + + + + + + + + + + + +
+ +
+
+ +
+
+ +
+ + + +``` + +其中: + +- `head`:调用方提供的头部片段,通常用于插入页面标题、meta 信息或当前页面需要的资源。 +- `content`:调用方提供的正文片段,应被插入到主题页面主体中。 + +主题可以自行决定外层容器、页头、页脚、暗黑模式、响应式布局等实现细节。建议保留 ``,以便 Halo 和插件继续向页面底部注入必要内容。 + +如果你的主题已经使用 `templates/layout.html` 作为内部公共模板,只要它声明了 `html(head, content)` 片段,就可以同时作为页面布局契约使用。如果这只是主题内部私有模板,建议改用 `templates/modules/layout.html` 等其他路径,避免被识别为插件页面集成布局。 + +## 插件页面调用布局 + +插件模板可以通过 `layout :: html(...)` 调用当前主题的页面布局: + +```html title="src/main/resources/templates/moment.html" + + + + 瞬间 - [[${site.title}]] + + +
+ +
+
+ +``` + +`layout` 是 Halo 为插件前台页面保留的集成模板名。这个特殊解析只对插件自身提供的模板生效,例如通过 `plugin::moment` 解析出的模板。即使插件包内存在 `templates/layout.html`,它也不会用于满足主题的页面布局契约。 + +插件内部私有布局应继续使用其他模板名,并通过 `plugin::` 前缀显式引用。详细方式可参考[在插件中提供主题模板](../plugin/api-reference/server/template-for-theme.md)。 + +## 兼容状态 + +主题安装、更新或重载后,Halo 会静态检查 `templates/layout.html`,并在 `Theme.status.pageLayout` 中记录兼容状态: + +- `SUPPORTED`:主题提供了符合 `html(head, content)` 契约的布局。 +- `MISSING`:主题未提供 `templates/layout.html`,使用布局契约的插件页面会使用 Halo 的 fallback 布局。 +- `INVALID`:主题提供了 `templates/layout.html`,但片段签名不符合当前契约。 + +缺失或异常不会让主题进入失败状态。Console 会在主题详情和主题列表中展示页面布局状态,帮助用户和主题开发者判断是否需要适配。 + +## 版本演进 + +当前 v1 契约只包含 `head` 和 `content` 两个片段参数。主题开发者不应假设调用方一定提供更多片段;插件开发者也不应依赖主题私有变量来渲染核心内容。后续如果需要新增插槽,Halo 会优先考虑新的片段名或新的契约版本,避免破坏已适配的主题。 diff --git a/docs/developer-guide/theme/structure.md b/docs/developer-guide/theme/structure.md index 72da5410..22587880 100644 --- a/docs/developer-guide/theme/structure.md +++ b/docs/developer-guide/theme/structure.md @@ -13,6 +13,7 @@ my-theme │ │ │ └── style.css │ │ └── js/ │ │ └── main.js +│ ├── layout.html │ ├── index.html │ ├── post.html │ ├── page.html @@ -30,6 +31,7 @@ my-theme 1. `/templates/` - 主题模板目录,存放主题模板文件,所有模板都需要放在这个目录。关于模板的详细说明,请查阅 [模板编写](./template-variables.md)。 2. `/templates/assets/` - 主题静态资源目录,存放主题的静态资源文件,目前静态资源文件只能放在这个目录,引用方式请查阅 [静态资源](./static-resources)。 -3. `/screenshot.png` - 可选的主题预览图文件,支持 `screenshot.png`、`screenshot.jpeg`、`screenshot.jpg` 和 `screenshot.webp`。Halo 会按此顺序识别第一个可读文件,用于 Console 主题预览,并通过 `Theme.status.screenshot` 暴露访问地址。 -4. `/theme.yaml` - 主题配置文件,配置主题的基本信息,如主题名称、版本、作者等。详细文档请查阅 [配置文件](./config)。 -5. `/settings.yaml` - 主题设置定义文件,配置主题的设置项表单。详细文档请查阅 [设置选项](./settings)。 +3. `/templates/layout.html` - 可选的页面布局契约模板,从 Halo 2.26.0 开始可用于让插件前台页面复用当前主题的页面外壳。详细文档请查阅 [页面布局契约](./page-layout.md)。 +4. `/screenshot.png` - 可选的主题预览图文件,支持 `screenshot.png`、`screenshot.jpeg`、`screenshot.jpg` 和 `screenshot.webp`。Halo 会按此顺序识别第一个可读文件,用于 Console 主题预览,并通过 `Theme.status.screenshot` 暴露访问地址。 +5. `/theme.yaml` - 主题配置文件,配置主题的基本信息,如主题名称、版本、作者等。详细文档请查阅 [配置文件](./config)。 +6. `/settings.yaml` - 主题设置定义文件,配置主题的设置项表单。详细文档请查阅 [设置选项](./settings)。 diff --git a/sidebars.js b/sidebars.js index 8903db91..a5e426aa 100644 --- a/sidebars.js +++ b/sidebars.js @@ -392,6 +392,7 @@ module.exports = { "developer-guide/theme/prepare", "developer-guide/theme/config", "developer-guide/theme/structure", + "developer-guide/theme/page-layout", "developer-guide/theme/static-resources", "developer-guide/theme/settings", "developer-guide/theme/annotations",