<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="/atom.xsl"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Hugo</title><subtitle>克喵的小站，记录着我的一些文字~</subtitle><link href="https://blog.518339.xyz/tags/hugo/" rel="alternate"/><link href="https://blog.518339.xyz/tags/hugo/atom.xml" rel="self" type="application/atom+xml"/><id>https://blog.518339.xyz/tags/hugo/</id><updated>2026-10-02T07:00:00+08:00</updated><generator uri="https://gohugo.io/">Hugo 0.166.0</generator><author><name>克喵Moretti</name><email>mcy@kemiaosw.top</email></author><entry><title>用 Pages CMS 写博客：从连接仓库到 AI 摘要</title><link href="https://blog.518339.xyz/p/pages-cms-writing-guide.html" rel="alternate"/><link rel="enclosure" href="https://cdn.jsdmirror.com/gh/kmoretti/piclist-img@main/img/6abcb99f8d703.webp" type="image/webp"/><id>https://blog.518339.xyz/p/pages-cms-writing-guide.html</id><published>2026-09-29T15:56:00+08:00</published><updated>2026-09-29T15:56:00+08:00</updated><author><name>克喵Moretti</name><email>mcy@kemiaosw.top</email></author><summary type="text">最近把这个博客接到了 Pages CMS。
之前写文章，通常是打开本地编辑器，找到 content/posts，新建一个 Markdown 文件，再手动检查 front matter、图片路径和构建结果。这个流程没有什么问题，只是每次想在别的电脑上改两句话，都要先找到仓库，再把环境准备好。
Pages CMS 解决的不是“怎么写 Markdown”这个问题，而是把这件事搬到了一个可以直接登录使用的网页里。文章仍然保存到 …</summary><content type="html"><![CDATA[<p>最近把这个博客接到了 Pages CMS。</p>
<p>之前写文章，通常是打开本地编辑器，找到 <code>content/posts</code>，新建一个 Markdown 文件，再手动检查 front matter、图片路径和构建结果。这个流程没有什么问题，只是每次想在别的电脑上改两句话，都要先找到仓库，再把环境准备好。</p>
<p>Pages CMS 解决的不是“怎么写 Markdown”这个问题，而是把这件事搬到了一个可以直接登录使用的网页里。文章仍然保存到 GitHub，Hugo 仍然负责构建，Cloudflare Pages 仍然负责发布，只是中间多了一个更适合写作的入口。</p>
<p>这篇文章把整个流程记下来：怎么连接仓库，怎么写第一篇文章，什么时候要切到 Source mode，以及文章保存以后，AI 摘要是怎么自动生成的。</p>
<h2 id="先看一遍发布链路">先看一遍发布链路</h2>
<p>这个项目没有把 CMS 当成一个独立的数据库。Pages CMS 改的还是仓库里的 Markdown 文件，保存后直接提交到 <code>main</code> 分支。</p>
<div class="solitude-tag tag-mermaid mermaid">flowchart LR
    A[Pages CMS 编辑文章] --&gt; B[提交到 GitHub main]
    B --&gt; C[GitHub Actions]
    C --&gt; D[补齐 AI 摘要]
    D --&gt; E[Hugo 构建]
    E --&gt; F[Cloudflare Pages 发布]</div>

<p>所以，一次正常发布大致会经过这些步骤：</p>
<ol>
<li>在 Pages CMS 中编辑或新建文章。</li>
<li>CMS 把修改提交到 <code>main</code>。</li>
<li>GitHub Actions 运行 <code>Deploy to Cloudflare Pages</code>。</li>
<li>对没有摘要的文章生成 <code>ai_summary</code>。</li>
<li>使用 Hugo Extended 构建站点并检查产物。</li>
<li>将站点部署到 Cloudflare Pages。</li>
</ol>
<p>Pages CMS 不需要再点击一个单独的“部署”按钮。文章提交成功后，后面的事情交给 Actions 就可以了。</p>




  

<aside class="solitude-tag note info flat no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-info"></i></span>
  <div class="note-content">这篇文章以仓库 <code>kemiao-moretti/meowloge</code> 为例。Pages CMS 连接的是这个 GitHub 仓库，Hugo 文章目录是 <code>content/posts</code>，不是仓库外层同名的目录。</div>
</aside>

<h2 id="连接-pages-cms">连接 Pages CMS</h2>
<h3 id="第一步登录">第一步：登录</h3>
<p>打开 <a href="https://app.pagescms.org/">Pages CMS</a>，使用 GitHub 登录。第一次进入时，需要授权 Pages CMS 访问 GitHub 仓库，按页面提示完成即可。</p>
<p>登录之后，选择博客对应的仓库：</p>
<figure class="code-block" data-code-block data-language="text">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">text</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-text">kemiao-moretti/meowloge</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>进入仓库后，确认当前查看的是 <code>main</code> 分支。这个项目采用直接提交 <code>main</code> 的方式，没有另外维护用于写作的 <code>edit</code> 分支。</p>
<h3 id="第二步确认内容集合">第二步：确认内容集合</h3>
<p>仓库根目录的 <code>.pages.yml</code> 是 Pages CMS 的配置文件。当前项目只开放两个内容集合：</p>
<ul>
<li><strong>Posts / 文章</strong>：对应 <code>content/posts</code>；</li>
<li><strong>Changelog / 更新日志</strong>：对应 <code>content/changelog</code>。</li>
</ul>
<p>第一次连接后，先确认这两个集合能正常显示。如果看到了 <code>_index.md</code>，不要把它当成普通文章编辑。它是 Hugo section 的索引文件，负责文章列表页的标题和描述。</p>
<details class="solitude-tag tag-fold" ><summary class="tag-fold-summary"><span class="tag-fold-title">为什么不直接在 CMS 里开放整个仓库？</span><span class="tag-fold-icon" aria-hidden="true"></span></summary><div class="tag-fold-content">因为文章只是这个项目的一部分。主题、Hugo 配置、工作流和脚本都属于站点实现，误改它们可能会让整站构建失败。CMS 只开放 Posts 和 Changelog，既能完成日常写作，也能把配置文件留在代码管理流程里。</div></details>

<h3 id="第三步配置自动发布所需的变量">第三步：配置自动发布所需的变量</h3>
<p>如果只是编辑已经有 <code>ai_summary</code> 的文章，CMS 本身不需要 AI Key。但新文章发布时，Actions 可能需要调用摘要接口，所以 GitHub 仓库里要提前配置好变量。</p>
<p>进入 GitHub 仓库的：</p>
<figure class="code-block" data-code-block data-language="text">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">text</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-text">Settings → Secrets and variables → Actions</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>在 <strong>Secrets</strong> 中配置：</p>
<table>
	<thead>
			<tr>
					<th>Secret</th>
					<th>用途</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>AI_SUMMARY_API_KEY</code></td>
					<td>AI 摘要服务的 API Key</td>
			</tr>
			<tr>
					<td><code>CLOUDFLARE_API_TOKEN</code></td>
					<td>部署 Cloudflare Pages</td>
			</tr>
			<tr>
					<td><code>CLOUDFLARE_ACCOUNT_ID</code></td>
					<td>Cloudflare 账户 ID</td>
			</tr>
	</tbody>
</table>
<p><code>AI_SUMMARY_API</code> 也可以作为 Secret 配置，用来覆盖默认的 OpenAI 兼容接口地址。</p>
<p>在 <strong>Variables</strong> 中可以配置：</p>
<table>
	<thead>
			<tr>
					<th>Variable</th>
					<th>用途</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>AI_SUMMARY_MODEL</code></td>
					<td>摘要使用的模型</td>
			</tr>
			<tr>
					<td><code>AI_SUMMARY_MAX_INPUT</code></td>
					<td>发送给模型的最大正文长度</td>
			</tr>
			<tr>
					<td><code>AI_SUMMARY_PROMPT</code></td>
					<td>自定义摘要提示词</td>
			</tr>
	</tbody>
</table>
<p>密钥只放在 GitHub Secrets 或本地 <code>.env</code>，不要写进 <code>.pages.yml</code>、<code>hugo.yaml</code>、文章 front matter 或正文代码块里。</p>
<h2 id="在-pages-cms-里写第一篇文章">在 Pages CMS 里写第一篇文章</h2>
<p>进入 <strong>Posts / 文章</strong> 集合，点击新建文章。这里的字段基本对应文章 front matter。</p>
<h3 id="这些字段怎么填">这些字段怎么填</h3>
<ul>
<li><code>title</code>：文章标题。</li>
<li><code>slug</code>：文章地址使用的小写英文标识，只允许小写字母、数字和连字符，例如 <code>pages-cms-writing-guide</code>。</li>
<li><code>date</code>：发布日期和时间，站点时区是 <code>Asia/Shanghai</code>。</li>
<li><code>description</code>：文章列表、搜索和分享时使用的描述。</li>
<li><code>cover</code>：可以填写 <code>/img/...</code> 的本地图片，也可以填写外部 HTTPS 图片地址。</li>
<li><code>categories</code>、<code>tags</code>、<code>series</code>：按需要填写数组。</li>
<li><code>toc</code>：文章较长、需要目录时打开。</li>
<li><code>comment</code>：是否开启评论。</li>
<li><code>locate</code>：文章位置说明，不需要时可以留空。</li>
<li><code>recommend</code>：只有确实要推荐文章时才打开。</li>
</ul>
<p>新文章的文件名由 <code>slug</code> 生成：</p>
<figure class="code-block" data-code-block data-language="text">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">text</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-text">content/posts/&lt;slug&gt;.md</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>这个博客的文章链接由 Hugo 配置为 <code>/p/:slug</code>，所以 slug 不是一个随手填写的内部字段。文章发布以后，尽量不要再改它，否则公开 URL 也会跟着变化。</p>




  

<aside class="solitude-tag note warning simple no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-triangle-exclamation"></i></span>
  <div class="note-content">已有文章不要修改 slug。Pages CMS 已经关闭了文章重命名操作，但填写新文章时仍然建议使用简短、稳定、全小写的英文 slug。</div>
</aside>

<h3 id="普通内容用-editor-mode">普通内容用 Editor mode</h3>
<p>标题、段落、列表、普通链接和普通图片，都可以直接使用 Pages CMS 的 Editor mode。这个模式适合日常写作，写完之后看起来和普通 Markdown 编辑器差不多。</p>
<p>例如下面这段内容不需要特殊处理：</p>
<figure class="code-block" data-code-block data-language="markdown">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">markdown</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-markdown">## 这是一节标题

这里是一段普通正文，里面可以放一个[站外链接](https://gohugo.io/)。

- 第一项
- 第二项</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>写作时可以先不用考虑 AI 摘要。正文保存后，后面的工作流会自动处理它。</p>
<h3 id="遇到-shortcode-就切换-source-mode">遇到 shortcode 就切换 Source mode</h3>
<p>这个主题提供了不少 Hugo shortcode，比如提示框、折叠面板、标签页、Mermaid 和卡片。Pages CMS 不负责解析它们，只是把文章里的 Markdown 保存回 GitHub。</p>
<p>因此，正文里出现下面这些内容时，建议切换到 <strong>Source mode</strong>：</p>
<ul>
<li><code>{{&lt; note &gt;}}</code>、<code>{{&lt; fold &gt;}}</code> 这类 Hugo shortcode；</li>
<li>Mermaid 流程图或 Chart.js 数据；</li>
<li>复杂 HTML；</li>
<li>shortcode 的示例代码；</li>
<li>需要保留精确缩进、空格和成对标签的内容。</li>
</ul>
<p>比如这段提示框就应该在 Source mode 中编辑：</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; note type=&#34;success&#34; &gt;}}
文章已经保存，接下来等待 GitHub Actions 构建。
{{&lt; /note &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>这里代码块里的 <code>/*</code> 和 <code>*/</code> 是为了让示例原样显示，实际文章中使用 shortcode 时不需要加这层转义。</p>
<p>如果把包含大量 shortcode 的文章交给 Editor mode，编辑器可能会重新排列 Markdown，或者把 shortcode 当成普通文本处理。文章看起来可能没问题，但构建时才发现标签没有闭合。遇到这类文章，Source mode 更稳妥。</p>
<h3 id="图片怎么上传">图片怎么上传</h3>
<p>Pages CMS 的媒体配置指向 <code>static/img</code>，文章正文图片建议放在：</p>
<figure class="code-block" data-code-block data-language="text">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">text</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-text">static/img/posts/</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>上传后，在文章中使用公开路径：</p>
<figure class="code-block" data-code-block data-language="markdown">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">markdown</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-markdown">![文章示例](/img/posts/example.webp)</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>提交前检查三件事：</p>
<ol>
<li>GitHub 中的文件确实位于 <code>static/img/posts/</code>；</li>
<li>Markdown 里的文件名大小写和实际文件一致；</li>
<li>引用使用 <code>/img/posts/...</code>，而不是 <code>static/img/posts/...</code>。</li>
</ol>
<p>图片不会放进 <code>content/posts</code>。文章目录存 Markdown，静态资源目录存图片，这是 Hugo 处理静态文件的方式。</p>
<h2 id="保存之后会发生什么">保存之后会发生什么</h2>
<p>在 CMS 中保存文章以后，先确认页面提示已经提交成功，再打开 GitHub Actions 查看 <code>Deploy to Cloudflare Pages</code>。</p>
<p>Actions 会先运行摘要脚本。它会读取 <code>content/posts</code> 下的文章，清理 front matter、代码块、图片地址、HTML 标签和 Markdown 符号，然后把正文发送给配置好的 OpenAI 兼容接口。</p>
<p>生成结果会写回 front matter：</p>
<figure class="code-block" data-code-block data-language="yaml">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">yaml</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-yaml">ai_summary: &gt;-
  这里是根据文章内容生成的一段中文摘要。</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>随后 Hugo 使用带有摘要的工作树继续构建，Cloudflare Pages 部署的也是这次构建结果。</p>







<article
  class="solitude-tag card_box tag-card no-cover has-action"
  style="width:100%;"
>
  
  <div class="card_body">
    <div class="card_top">
      
      <span class="card_tag">已有说明</span>
    </div>
    <div class="card_mask card_info">
      <div class="card_content">
        <span class="card_title">AI 摘要只在构建期生成</span>
        <span class="card_description">浏览器只负责展示 front matter 中已经存在的摘要，不会在访客打开文章时请求 AI 接口。API Key 不会进入前端。</span>
      </div>
      <div class="card_footer">
        <div class="card_rating" aria-label="评分 5 / 5">
          <i class="fa-solid fa-star" aria-hidden="true"></i>
        </div>
        
          <a
            class="card_action"
            href="/p/ai-summary"
            aria-label="查看详情：AI 摘要只在构建期生成"
            
          ><i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a>
        
      </div>
    </div>
  </div>
</article>

<h3 id="普通发布不会重复生成">普通发布不会重复生成</h3>
<p>摘要脚本默认只处理没有 <code>ai_summary</code> 的文章。这样修改一篇已有文章时，不会因为普通发布再次消耗模型额度，也不会让摘要在每次构建时发生变化。</p>
<p>如果确实需要重新生成已有文章的摘要，可以在 GitHub Actions 页面手动运行工作流，并把：</p>
<figure class="code-block" data-code-block data-language="text">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">text</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-text">force_summaries = true</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>设为 <code>true</code>。</p>
<p>有一种情况会始终跳过：文章明确写了：</p>
<figure class="code-block" data-code-block data-language="yaml">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">yaml</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-yaml">ai_summary: false</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>这表示作者不希望这篇文章生成摘要。普通发布和强制重新生成都不会覆盖这个停用标记。</p>
<h3 id="本地也可以先试跑">本地也可以先试跑</h3>
<p>如果想在提交前检查哪些文章会被处理，可以在博客仓库根目录执行：</p>
<figure class="code-block" data-code-block data-language="bash">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">bash</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-bash">node scripts/generate-ai-summary.mjs --dry-run</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>这条命令只列出候选文章，不调用 AI 接口，也不会修改文件。确认配置和文章都没有问题后，再运行完整命令：</p>
<figure class="code-block" data-code-block data-language="bash">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">bash</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-bash">node scripts/generate-ai-summary.mjs
hugo --gc --minify</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>本地摘要配置放在 <code>.env</code> 中：</p>
<figure class="code-block" data-code-block data-language="dotenv">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">dotenv</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-dotenv">AI_SUMMARY_API=https://api.siliconflow.cn/v1/chat/completions
AI_SUMMARY_API_KEY=你的 API Key
AI_SUMMARY_MODEL=Qwen/Qwen3-8B</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p><code>.env</code> 已经被 Git 忽略。不要把真实 Key 填进 <code>.env.example</code>，更不要把它放进文章里作为示例提交。</p>
<h2 id="几个容易踩到的地方">几个容易踩到的地方</h2>
<h3 id="source-mode-和-editor-mode-混着用">Source mode 和 Editor mode 混着用</h3>
<p>普通段落用 Editor mode 没问题，但一篇文章只要包含多个 shortcode，最好从头到尾在 Source mode 中检查一次。尤其要确认：</p>
<ul>
<li>每个块级 shortcode 都有对应的结束标签；</li>
<li>Mermaid、Chart.js 的内容仍然是合法格式；</li>
<li>代码块中的 shortcode 示例没有被提前解析；</li>
<li>HTML 标签的引号和缩进没有被编辑器改坏。</li>
</ul>
<h3 id="ai-摘要失败后继续等部署">AI 摘要失败后继续等部署</h3>
<p>摘要接口返回错误、Key 缺失、模型名称错误或接口超时，Actions 会失败，后面的 Hugo 构建和 Cloudflare 部署不会继续执行。</p>
<p>这时先看 Actions 日志中的失败文件和错误信息，检查 <code>AI_SUMMARY_API_KEY</code>、接口地址、模型名称以及服务商状态。配置修好后，在原来的 workflow 页面重新运行即可。</p>
<h3 id="把摘要当成-seo-描述">把摘要当成 SEO 描述</h3>
<p><code>ai_summary</code> 是文章正文前的展示内容，<code>description</code> 才是文章的描述字段。两者用途不同，不要为了显示摘要而删掉 <code>description</code>，也不要把 API 返回结果直接塞进站点全局配置。</p>




  

<aside class="solitude-tag note success modern no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-check"></i></span>
  <div class="note-content">写作时只需要关注标题、正文、图片和文章元数据。保存以后，让 Pages CMS 提交 GitHub，再让 Actions 负责摘要、构建和部署，整个流程就串起来了。</div>
</aside>

<h2 id="最后检查一下">最后检查一下</h2>
<p>现在这套流程可以概括成一句话：Pages CMS 负责写，GitHub 负责存，Actions 负责补齐摘要和构建，Cloudflare Pages 负责发布。</p>
<p>第一次使用时，我建议按下面的顺序走一遍：</p>
<ol>
<li>连接 <code>kemiao-moretti/meowloge</code>，确认分支是 <code>main</code>。</li>
<li>检查 Posts 集合是否对应 <code>content/posts</code>。</li>
<li>创建一篇测试文章，使用英文 slug。</li>
<li>普通正文用 Editor mode，包含 shortcode 时切到 Source mode。</li>
<li>上传一张图片，确认它最终位于 <code>static/img/posts/</code>。</li>
<li>保存后查看 GitHub commit 和 Actions 运行结果。</li>
<li>打开文章，确认摘要显示在正文前，图片、代码块和 shortcode 都正常。</li>
</ol>
<p>这样以后想写文章时，不必先打开本地开发环境。打开 Pages CMS，写完，保存，等它跑完发布流程就可以了。偶尔需要改主题或调脚本时，再回到仓库里处理，两套入口各自负责擅长的事情，反而更清楚。</p>
]]></content><category term="博客魔改" scheme="category"/><category term="博客魔改" scheme="series"/><category term="Pages CMS" scheme="tag"/><category term="Hugo" scheme="tag"/><category term="GitHub Actions" scheme="tag"/><category term="AI" scheme="tag"/></entry><entry><title>Solitude Hugo Shortcode 使用指南</title><link href="https://blog.518339.xyz/p/shortcode-showcase.html" rel="alternate"/><link rel="enclosure" href="https://blog.518339.xyz/img/posts/cover-shortcodes-v2.webp" type="image/webp"/><id>https://blog.518339.xyz/p/shortcode-showcase.html</id><published>2026-08-22T10:00:00+08:00</published><updated>2026-10-02T07:00:00+08:00</updated><author><name>克喵Moretti</name><email>mcy@kemiaosw.top</email></author><summary type="text">Shortcode 是 Hugo 在 Markdown 之外提供的内容组件语法。Solitude 用它承载提示框、标签页、图库、图表等富内容；迁移旧文章时，也应把 Hexo 外挂标签改写为对应的 Hugo shortcode。
本文既是使用手册，也是可构建的效果页。每个组件都按 用途 → 写法 → 参数 → 效果 展开，代码可以直接复制到 Markdown 文件中。 开始之前 Hugo shortcode 有两种边界符：{{&amp;amp;lt; …</summary><content type="html"><![CDATA[<p>Shortcode 是 Hugo 在 Markdown 之外提供的内容组件语法。Solitude 用它承载提示框、标签页、图库、图表等富内容；迁移旧文章时，也应把 Hexo 外挂标签改写为对应的 Hugo shortcode。</p>




  

<aside class="solitude-tag note info flat no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-info"></i></span>
  <div class="note-content">本文既是使用手册，也是可构建的效果页。每个组件都按 <strong>用途 → 写法 → 参数 → 效果</strong> 展开，代码可以直接复制到 Markdown 文件中。</div>
</aside>

<h2 id="开始之前">开始之前</h2>
<p>Hugo shortcode 有两种边界符：<code>{{&lt; shortcode &gt;}}</code> 适合普通参数，<code>{{% shortcode %}}</code> 会先处理内部 Markdown。Solitude 的块级组件已经按各自用途处理正文，通常直接使用尖括号写法即可。</p>
<table>
	<thead>
			<tr>
					<th>内容类型</th>
					<th>推荐组件</th>
					<th>适合场景</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>行内强调</td>
					<td><code>span</code>、<code>label</code>、<code>keyboard</code></td>
					<td>一句话中的状态、术语或快捷键</td>
			</tr>
			<tr>
					<td>块级提示</td>
					<td><code>note</code>、<code>subnote</code>、<code>fold</code></td>
					<td>说明、警告、补充资料</td>
			</tr>
			<tr>
					<td>导航与引用</td>
					<td><code>button</code>、<code>link</code>、<code>card</code></td>
					<td>行动入口、站内外资源</td>
			</tr>
			<tr>
					<td>结构化内容</td>
					<td><code>tabs</code>、<code>timeline</code>、<code>gallery</code>、<code>series</code></td>
					<td>分组、步骤、图片与文章集合</td>
			</tr>
			<tr>
					<td>动态内容</td>
					<td><code>mermaid</code>、<code>chartjs</code>、<code>typeit</code></td>
					<td>流程、数据与动态文字</td>
			</tr>
	</tbody>
</table>




  

<aside class="solitude-tag note warning simple no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-triangle-exclamation"></i></span>
  <div class="note-content">Shortcode 名称和参数区分大小写。块级组件还要成对书写结束标签，否则 Hugo 会在构建阶段直接报错。</div>
</aside>

<h2 id="文本与状态">文本与状态</h2>
<h3 id="彩色文本与标签">彩色文本与标签</h3>
<p><code>p</code> 用于整段文字，<code>span</code> 用于行内文字，<code>label</code> 用于短小的状态标记。颜色参数可使用 <code>blue</code>、<code>green</code>、<code>orange</code>、<code>red</code>、<code>purple</code> 等主题色名称。</p>
<p><strong>写法</strong></p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; p color=&#34;blue&#34; &gt;}}这是一段蓝色文字{{&lt; /p &gt;}}
正文中的 {{&lt; span color=&#34;red&#34; &gt;}}重点文字{{&lt; /span &gt;}}
{{&lt; label color=&#34;green&#34; &gt;}}已完成{{&lt; /label &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p><strong>效果</strong></p>
<p class="solitude-tag tag-text tag-paragraph blue">这是一段蓝色文字，用于在正文中形成较强的段落提示。</p>

<p>正文中的 <span class="solitude-tag tag-text tag-span red">重点文字</span>
 可以和普通内容自然排列。</p>
<p><mark class="solitude-tag hl-label tag-label green">已完成</mark>

<mark class="solitude-tag hl-label tag-label blue">信息</mark>

<mark class="solitude-tag hl-label tag-label orange">注意</mark>

<mark class="solitude-tag hl-label tag-label purple">扩展</mark>
</p>
<h3 id="提示框">提示框</h3>
<p><code>note</code> 是主要提示组件，<code>subnote</code> 适合在一个主题下继续补充次级信息。</p>
<p><strong>写法</strong></p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; note type=&#34;info&#34; style=&#34;flat&#34; &gt;}}
提示内容，支持 Markdown。
{{&lt; /note &gt;}}

{{&lt; subnote type=&#34;warning&#34; &gt;}}次级提示{{&lt; /subnote &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>是否必填</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>type</code></td>
					<td>否</td>
					<td><code>info</code>、<code>success</code>、<code>warning</code>、<code>danger</code>、<code>primary</code> 或默认样式</td>
			</tr>
			<tr>
					<td><code>style</code></td>
					<td>否</td>
					<td><code>flat</code>、<code>simple</code>、<code>modern</code>；默认使用 <code>flat</code></td>
			</tr>
			<tr>
					<td>正文</td>
					<td>是</td>
					<td>支持 Markdown 的提示内容</td>
			</tr>
	</tbody>
</table>
<p><strong>效果</strong></p>
<p>



  

<aside class="solitude-tag note info flat no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-info"></i></span>
  <div class="note-content">信息提示适合解释前置条件或补充背景。</div>
</aside>





  

<aside class="solitude-tag note success modern no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-check"></i></span>
  <div class="note-content">构建与内容检查已经通过，可以继续发布流程。</div>
</aside>





  

<aside class="solitude-tag note warning simple no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-triangle-exclamation"></i></span>
  <div class="note-content">修改配置后请重新构建站点，避免继续使用旧的资源指纹。</div>
</aside>





  

<aside class="solitude-tag note danger flat no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-exclamation"></i></span>
  <div class="note-content">危险提示应只用于确实需要读者立即注意的问题。</div>
</aside>




  

<aside class="solitude-tag note subnote warning flat no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-triangle-exclamation"></i></span>
  <div class="note-content">这是紧跟主要内容的次级提醒。</div>
</aside>
</p>
<h3 id="选择快捷键与隐藏文字">选择、快捷键与隐藏文字</h3>
<p>这组组件适合展示只读状态和行内补充信息。<code>checkbox</code> 与 <code>radio</code> 仅负责表达，不会提交表单。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; checkbox checked=true &gt;}}已完成事项{{&lt; /checkbox &gt;}}
{{&lt; radio checked=false &gt;}}未选择事项{{&lt; /radio &gt;}}
{{&lt; keyboard &gt;}}⌘ K{{&lt; /keyboard &gt;}}
{{&lt; spoiler &gt;}}移入或聚焦后显示{{&lt; /spoiler &gt;}}
{{&lt; bubble position=&#34;left&#34; &gt;}}气泡消息{{&lt; /bubble &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p><div class="solitude-tag checkbox tag-choice "><input type="checkbox" aria-label="已完成事项" checked disabled><span class="tag-choice-content">已完成事项</span></div>

<div class="solitude-tag checkbox tag-choice blue"><input type="checkbox" aria-label="尚未完成事项"  disabled><span class="tag-choice-content">尚未完成事项</span></div>

<div class="solitude-tag checkbox tag-choice "><input type="radio" aria-label="已选择事项" checked disabled><span class="tag-choice-content">已选择事项</span></div>

<div class="solitude-tag checkbox tag-choice plus"><input type="checkbox" aria-label="新增检查项" checked disabled><span class="tag-choice-content">新增检查项</span></div>
</p>
<p>按下 <kbd class="solitude-tag keyboard-tag tag-keyboard">⌘ K</kbd>
 打开搜索；答案是 <span class="solitude-tag spoiler tag-spoiler block-text" tabindex="0" aria-label="Hidden text">隐藏内容</span>
。<span class="solitude-tag bubble tag-bubble"><span class="bubble-content" tabindex="0">气泡消息</span><span class="bubble-notation bg-blue">left</span></span>
</p>
<h2 id="链接按钮与媒体">链接、按钮与媒体</h2>
<h3 id="按钮与链接卡片">按钮与链接卡片</h3>
<p><code>button</code> 提供主题按钮，并通过 <code>option</code> 组合颜色、描边和整行样式；<code>link</code> 将链接呈现为带说明的资源卡片。站外链接会自动在新窗口打开并附带安全属性。</p>
<p><strong>写法</strong></p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; button url=&#34;https://gohugo.io/&#34; text=&#34;Hugo 官网&#34; icon=&#34;fas fa-link&#34; &gt;}}
{{&lt; button url=&#34;/&#34; text=&#34;描边按钮&#34; icon=&#34;fas fa-house&#34; option=&#34;blue outline&#34; &gt;}}
{{&lt; link url=&#34;/&#34; title=&#34;站内链接&#34; desc=&#34;返回示例站首页&#34; &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>适用组件</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>url</code></td>
					<td>全部</td>
					<td>目标地址</td>
			</tr>
			<tr>
					<td><code>text</code></td>
					<td><code>button</code></td>
					<td>按钮文字</td>
			</tr>
			<tr>
					<td><code>icon</code></td>
					<td><code>button</code></td>
					<td>图标类名</td>
			</tr>
			<tr>
					<td><code>option</code></td>
					<td><code>button</code></td>
					<td>可组合 <code>outline</code>、颜色、<code>block</code> 等样式</td>
			</tr>
			<tr>
					<td><code>title</code> / <code>desc</code></td>
					<td><code>link</code></td>
					<td>卡片标题与说明</td>
			</tr>
	</tbody>
</table>
<p><strong>效果</strong></p>
<p><a class="solitude-tag st-btn tag-button  has-icon " href="https://gohugo.io/" target="_blank" rel="noopener noreferrer"><i class="solitude fas fa-arrow-up-right-from-square" aria-hidden="true"></i><span>Hugo 官网</span></a>

<a class="solitude-tag st-btn tag-button blue outline has-icon " href="/" ><i class="solitude fas fa-house" aria-hidden="true"></i><span>描边按钮</span></a>

<a class="solitude-tag st-btn tag-button block has-icon " href="/" ><i class="solitude fas fa-arrow-right" aria-hidden="true"></i><span>适合移动端换行的整行按钮</span></a>
</p>
<p><div class="solitude-tag tag-link-card"><a class="solitude-tag tag-link" href="https://gohugo.io/" target="_blank" rel="noopener noreferrer" aria-label="Hugo：The world’s fastest framework for building websites"><div class="tag-link-tips"><i class="fas fa-arrow-up-right-from-square" aria-hidden="true"></i>引用站外链接</div><div class="tag-link-bottom"><div class="tag-link-left"><i class="solitude fas fa-link"></i></div><div class="tag-link-right"><div class="tag-link-title">Hugo</div><div class="tag-link-sitename">The world’s fastest framework for building websites</div></div><i class="solitude fas fa-chevron-right"></i></div></a></div>

<div class="solitude-tag tag-link-card"><a class="solitude-tag tag-link" href="/"  aria-label="站内链接与超长标题在窄屏下的截断和换行验证：返回示例站首页，检查移动端触控面积与键盘焦点状态。"><div class="tag-link-tips"><i class="fas fa-house" aria-hidden="true"></i>站内链接</div><div class="tag-link-bottom"><div class="tag-link-left"><i class="solitude fas fa-link"></i></div><div class="tag-link-right"><div class="tag-link-title">站内链接与超长标题在窄屏下的截断和换行验证</div><div class="tag-link-sitename">返回示例站首页，检查移动端触控面积与键盘焦点状态。</div></div><i class="solitude fas fa-chevron-right"></i></div></a></div>
</p>
<h3 id="图片">图片</h3>
<p><code>img</code> 用于带说明的块级图片，<code>inlineImg</code> 用于跟随文字排列的小图片。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; img src=&#34;/img/default.avif&#34; alt=&#34;示例图片&#34; caption=&#34;主题默认封面&#34; &gt;}}
{{&lt; inlineImg src=&#34;/img/avatar.webp&#34; alt=&#34;Logo&#34; height=&#34;24px&#34; &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<figure class="solitude-tag tag-image-wrap"><img class="solitude-tag tag-image" src="/img/demo/cover-shortcodes-v2.webp" alt="Solitude Shortcode 示例封面" loading="lazy" ><figcaption>本地 Shortcode 示例素材</figcaption></figure>

<p>Solitude <img class="solitude-tag inline-img tag-inline-image no-lightbox" src="/img/avatar.webp" alt="Solitude Logo" style="height:24px" loading="lazy">
 与 Hugo 可以出现在同一行文字中。</p>
<h3 id="视频与音频">视频与音频</h3>
<p>YouTube、哔哩哔哩、原生音频和原生视频分别使用独立组件。外部媒体是否可播放仍取决于来源站点、网络环境与浏览器策略。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; youtube id=&#34;dQw4w9WgXcQ&#34; &gt;}}
{{&lt; bvideo bvid=&#34;BV1xx411c7mD&#34; &gt;}}
{{&lt; audio url=&#34;/media/example.mp3&#34; name=&#34;示例音频&#34; &gt;}}
{{&lt; video url=&#34;/media/example.mp4&#34; poster=&#34;/img/default.avif&#34; &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p><div class="solitude-tag video-container tag-video-embed tag-video-youtube"><iframe src="https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ" title="YouTube video player" loading="lazy" allowfullscreen></iframe></div>

<div class="solitude-tag video-container tag-video-embed tag-video-bilibili"><iframe src="https://player.bilibili.com/player.html?autoplay=0&bvid=BV1xx411c7mD" title="Bilibili video player" loading="lazy" allowfullscreen></iframe></div>

<div class="solitude-tag audio tag-audio"><span class="tag-media-icon" aria-hidden="true"><i class="fas fa-music"></i></span><audio controls preload="metadata" aria-label="本地示例音频"><source src="/media/shortcodes/t-rex-roar.mp3">Your browser does not support the audio tag.</audio></div>

<div class="solitude-tag video tag-video"><video controls preload="metadata" poster="/img/demo/cover-shortcodes-v2.webp"><source src="/media/shortcodes/flower.mp4">Your browser does not support the video tag.</video></div>
</p>
<h2 id="折叠隐藏与卡片">折叠、隐藏与卡片</h2>
<h3 id="折叠面板">折叠面板</h3>
<p><code>fold</code> 使用原生 <code>details</code> 结构，支持鼠标、触摸和键盘操作。添加 <code>open=true</code> 可让内容默认展开。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; fold title=&#34;展开内容&#34; open=true &gt;}}
折叠区域内支持 **Markdown**。
{{&lt; /fold &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<details class="solitude-tag tag-fold" ><summary class="tag-fold-summary"><span class="tag-fold-title">展开内容</span><span class="tag-fold-icon" aria-hidden="true"></span></summary><div class="tag-fold-content">折叠区域内支持 <strong>Markdown</strong>。</div></details>

<details class="solitude-tag tag-fold" open><summary class="tag-fold-summary"><span class="tag-fold-title">默认展开的长标题折叠面板，用于检查移动端省略和多行正文布局</span><span class="tag-fold-icon" aria-hidden="true"></span></summary><div class="tag-fold-content">展开状态同样使用柔和表面、清晰分隔和可见的键盘焦点，不依赖鼠标悬停。</div></details>

<h3 id="点击后显示">点击后显示</h3>
<p>三个隐藏组件的区别只在呈现方式：<code>hideInline</code> 适合一句话，<code>hideBlock</code> 适合独立内容块，<code>hideToggle</code> 适合带标题的可切换区域。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; hideInline text=&#34;查看答案&#34; &gt;}}答案{{&lt; /hideInline &gt;}}
{{&lt; hideBlock text=&#34;展开内容&#34; &gt;}}块级内容{{&lt; /hideBlock &gt;}}
{{&lt; hideToggle title=&#34;阅读更多&#34; &gt;}}可切换内容{{&lt; /hideToggle &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p>哪个组件适合藏在一句话里？<span class="solitude-tag tag-hide tag-hide-inline"><button type="button" class="tag-hide-button" aria-expanded="false" aria-controls="tag-hide-content-33">查看答案</button><span id="tag-hide-content-33" class="tag-hide-content" hidden>hideInline</span></span>
</p>
<p><div class="solitude-tag tag-hide tag-hide-block"><button type="button" class="tag-hide-button" aria-expanded="false" aria-controls="tag-hide-content-34">点击展开</button><div id="tag-hide-content-34" class="tag-hide-content" hidden>块级隐藏内容可以包含 <strong>Markdown</strong>。</div></div>

<div class="solitude-tag tag-hide tag-hide-toggle"><button type="button" class="tag-hide-button" aria-expanded="false" aria-controls="tag-hide-content-35">可切换内容</button><div id="tag-hide-content-35" class="tag-hide-content" hidden>这里同样支持 Markdown，并保留明确的展开状态。</div></div>
</p>
<h3 id="内容卡片">内容卡片</h3>
<p><code>card</code> 用于推荐项目、文章或资源。封面是可选项，没有封面时会自动切换到纯内容布局。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; card title=&#34;Hugo 卡片&#34; url=&#34;https://gohugo.io/&#34;
    cover=&#34;/img/default.avif&#34; tag=&#34;资源&#34; star=&#34;5&#34; &gt;}}
卡片说明
{{&lt; /card &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>title</code></td>
					<td>卡片标题，也可使用 <code>name</code></td>
			</tr>
			<tr>
					<td><code>url</code></td>
					<td>可选的跳转地址</td>
			</tr>
			<tr>
					<td><code>cover</code></td>
					<td>可选封面，也可使用 <code>bg</code></td>
			</tr>
			<tr>
					<td><code>tag</code> / <code>star</code></td>
					<td>分类标签与评分</td>
			</tr>
			<tr>
					<td><code>width</code> / <code>height</code></td>
					<td>可选尺寸，建议优先沿用默认响应式宽度</td>
			</tr>
	</tbody>
</table>
<p>






<article
  class="solitude-tag card_box tag-card has-cover has-action"
  style="width:100%;"
>
  
    <div class="card_cover" aria-hidden="true" style="background-image:url('/img/demo/cover-shortcodes-v2.webp')"></div>
  
  <div class="card_body">
    <div class="card_top">
      
      <span class="card_tag">封面卡片</span>
    </div>
    <div class="card_mask card_info">
      <div class="card_content">
        <span class="card_title">Hugo 卡片</span>
        <span class="card_description">展示主题与重点内容</span>
      </div>
      <div class="card_footer">
        <div class="card_rating" aria-label="评分 5 / 5">
          <i class="fa-solid fa-star" aria-hidden="true"></i>
        </div>
        
          <a
            class="card_action"
            href="https://gohugo.io/"
            aria-label="查看详情：Hugo 卡片"
            target="_blank" rel="noopener noreferrer"
          ><i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a>
        
      </div>
    </div>
  </div>
</article>








<article
  class="solitude-tag card_box tag-card no-cover has-action"
  style="width:100%;"
>
  
  <div class="card_body">
    <div class="card_top">
      
      <span class="card_tag">纯内容</span>
    </div>
    <div class="card_mask card_info">
      <div class="card_content">
        <span class="card_title">无封面卡片</span>
        <span class="card_description">简洁，也保持完整层级</span>
      </div>
      <div class="card_footer">
        <div class="card_rating" aria-label="评分 4 / 5">
          <i class="fa-solid fa-star" aria-hidden="true"></i>
        </div>
        
          <a
            class="card_action"
            href="https://gohugo.io/"
            aria-label="查看详情：无封面卡片"
            target="_blank" rel="noopener noreferrer"
          ><i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a>
        
      </div>
    </div>
  </div>
</article>
</p>
<h2 id="数据与可视化">数据与可视化</h2>
<h3 id="mermaid-流程图">Mermaid 流程图</h3>
<p><code>mermaid</code> 直接接收 Mermaid 语法，适合流程图、时序图、状态图等结构化图形。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; mermaid &gt;}}
flowchart LR
  Hexo --&gt; Hugo
  Hugo --&gt; HTML
{{&lt; /mermaid &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag tag-mermaid mermaid">flowchart LR
Hexo --&gt; Hugo
Hugo --&gt; HTML</div>

<h3 id="chartjs-图表">Chart.js 图表</h3>
<p><code>chartjs</code> 支持 <code>id</code>、<code>layout</code>、<code>width</code> 和 <code>description</code> 参数。正文必须是合法 JSON。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; chartjs description=&#34;三期构建趋势&#34; &gt;}}
{&#34;type&#34;:&#34;line&#34;,&#34;data&#34;:{&#34;labels&#34;:[&#34;一&#34;,&#34;二&#34;,&#34;三&#34;],&#34;datasets&#34;:[{&#34;label&#34;:&#34;趋势&#34;,&#34;data&#34;:[1,3,2]}]}}
{{&lt; /chartjs &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag chartjs-container tag-chart " data-chartjs-id="chartjs-39" ><pre class="chartjs-src" hidden>{&#34;type&#34;:&#34;line&#34;,&#34;data&#34;:{&#34;labels&#34;:[&#34;一&#34;,&#34;二&#34;,&#34;三&#34;],&#34;datasets&#34;:[{&#34;label&#34;:&#34;趋势&#34;,&#34;data&#34;:[1,3,2]}]}}</pre><div class="chartjs-desc">三期构建趋势</div></div>

<h3 id="乐谱与动态文字">乐谱与动态文字</h3>
<p><code>score</code> 使用 ABC 记谱文本，<code>typeit</code> 用 <code>speed</code> 控制逐字显示速度。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; typeit speed=&#34;60&#34; &gt;}}TypeIt 动态文本{{&lt; /typeit &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag abc-music-sheet tag-score" data-params="{}" aria-label="Music notation">X:1
T:Hugo migration
M:4/4
K:C
C D E F|G A B c|</div>

<div class="solitude-tag tag-typeit typeit"><span id="typeit-41" data-typeit data-speed="60">TypeIt 动态文本</span></div>

<h2 id="仓库与站点资源">仓库与站点资源</h2>
<h3 id="仓库卡片">仓库卡片</h3>
<p>四个仓库组件使用同样的 <code>repo=&quot;组织/仓库&quot;</code> 写法；自建 Gitea 还需要提供 <code>host</code>。仓库数据由浏览器访问对应平台 API，因此加载状态可能受网络或频率限制影响。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; github repo=&#34;gohugoio/hugo&#34; &gt;}}
{{&lt; gitlab repo=&#34;gitlab-org/gitlab&#34; &gt;}}
{{&lt; gitee repo=&#34;mirrors/hugo&#34; &gt;}}
{{&lt; gitea repo=&#34;go-gitea/gitea&#34; host=&#34;https://gitea.com&#34; &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<p><article class="solitude-tag repo-card tag-repo" data-repo-provider="github" data-repo-endpoint="https://api.github.com/repos/gohugoio/hugo" aria-busy="true"><div class="repo-card-header"><span class="repo-provider"><i class="fab fa-github" aria-hidden="true"></i>GitHub</span><img class="repo-language no-lightbox" alt="" loading="lazy" hidden></div><a class="repo-title" href="https://github.com/gohugoio/hugo" target="_blank" rel="noopener noreferrer">hugo</a><p class="repo-desc">正在读取仓库信息…</p><div class="repo-card-footer"><div class="repo-gist" aria-label="Repository statistics"><span><i class="fas fa-star" aria-hidden="true"></i><span class="repo-stars">—</span></span><span><i class="fas fa-code-branch" aria-hidden="true"></i><span class="repo-forks">—</span></span></div><span class="repo-status" role="status">加载中</span></div></article>


<article class="solitude-tag repo-card tag-repo" data-repo-provider="gitlab" data-repo-endpoint="https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab" aria-busy="true"><div class="repo-card-header"><span class="repo-provider"><i class="fab fa-gitlab" aria-hidden="true"></i>GitLab</span><img class="repo-language no-lightbox" alt="" loading="lazy" hidden></div><a class="repo-title" href="https://gitlab.com/gitlab-org/gitlab" target="_blank" rel="noopener noreferrer">gitlab</a><p class="repo-desc">正在读取仓库信息…</p><div class="repo-card-footer"><div class="repo-gist" aria-label="Repository statistics"><span><i class="fas fa-star" aria-hidden="true"></i><span class="repo-stars">—</span></span><span><i class="fas fa-code-branch" aria-hidden="true"></i><span class="repo-forks">—</span></span></div><span class="repo-status" role="status">加载中</span></div></article>


<article class="solitude-tag repo-card tag-repo" data-repo-provider="gitee" data-repo-endpoint="https://gitee.com/api/v5/repos/mirrors/hugo" aria-busy="true"><div class="repo-card-header"><span class="repo-provider"><i class="fab fa-git-alt" aria-hidden="true"></i>Gitee</span><img class="repo-language no-lightbox" alt="" loading="lazy" hidden></div><a class="repo-title" href="https://gitee.com/mirrors/hugo" target="_blank" rel="noopener noreferrer">hugo</a><p class="repo-desc">正在读取仓库信息…</p><div class="repo-card-footer"><div class="repo-gist" aria-label="Repository statistics"><span><i class="fas fa-star" aria-hidden="true"></i><span class="repo-stars">—</span></span><span><i class="fas fa-code-branch" aria-hidden="true"></i><span class="repo-forks">—</span></span></div><span class="repo-status" role="status">加载中</span></div></article>


<article class="solitude-tag repo-card tag-repo" data-repo-provider="gitea" data-repo-endpoint="https://gitea.com/api/v1/repos/go-gitea/gitea" aria-busy="true"><div class="repo-card-header"><span class="repo-provider"><i class="fab fa-git-alt" aria-hidden="true"></i>Gitea</span><img class="repo-language no-lightbox" alt="" loading="lazy" hidden></div><a class="repo-title" href="https://gitea.com/go-gitea/gitea" target="_blank" rel="noopener noreferrer">gitea</a><p class="repo-desc">正在读取仓库信息…</p><div class="repo-card-footer"><div class="repo-gist" aria-label="Repository statistics"><span><i class="fas fa-star" aria-hidden="true"></i><span class="repo-stars">—</span></span><span><i class="fas fa-code-branch" aria-hidden="true"></i><span class="repo-forks">—</span></span></div><span class="repo-status" role="status">加载中</span></div></article>

</p>
<h3 id="友链列表">友链列表</h3>
<p><code>flink</code> 的正文是 YAML 数据。一个组件可以包含多个分组，每个分组下可以继续放置多个站点。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; flink &gt;}}
- class_name: 官方资源
  class_desc: Hugo 官方网站
  link_list:
    - name: Hugo
      link: https://gohugo.io/
      avatar: https://gohugo.io/images/hugo-logo-wide.svg
      descr: 世界上最快的网站构建框架
{{&lt; /flink &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>

<div class="solitude-tag flink tag-flink">
  
    <div class="flink-name">官方资源</div>
    <div class="flink-desc">Hugo 官方网站</div>
    <div class="flink-list">
      
        <div class="flink-list-item">
          <a class="cf-friends-link" href="https://gohugo.io/" title="Hugo" target="_blank" rel="noopener noreferrer">
            <img class="flink-avatar cf-friends-avatar no-lightbox" src="https://gohugo.io/images/hugo-logo-wide.svg" alt="" loading="lazy">
            <div class="flink-item-info">
              <span class="flink-item-name cf-friends-name">Hugo</span>
              <span class="flink-item-desc" title="世界上最快的网站构建框架">世界上最快的网站构建框架</span>
            </div>
          </a>
        </div>
      
    </div>
  
</div>

<h2 id="布局与内容集合">布局与内容集合</h2>
<h3 id="图库与图库分组">图库与图库分组</h3>
<p><code>gallery</code> 负责瀑布流容器，内部使用 <code>galleryItem</code> 放置不同宽高的图片；<code>columns</code> 可指定桌面端列数。<code>galleryGroup</code> 则用于创建带封面、说明和链接的图库入口。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; gallery columns=&#34;2&#34; &gt;}}
{{&lt; galleryItem src=&#34;/img/default.avif&#34; alt=&#34;Gallery 1&#34; &gt;}}
{{&lt; galleryItem src=&#34;/img/default.avif&#34; alt=&#34;Gallery 2&#34; &gt;}}
{{&lt; galleryItem src=&#34;/img/default.avif&#34; alt=&#34;Gallery 3&#34; &gt;}}
{{&lt; galleryItem src=&#34;/img/default.avif&#34; alt=&#34;Gallery 4&#34; &gt;}}
{{&lt; /gallery &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag tag-gallery gallery-container" data-columns="2">
<div class="solitude-tag tag-gallery-item gallery-item"><img class="nolazyload" src="/img/demo/about/music-listening-v2.webp" alt="音乐主题示例图片" loading="lazy"></div>

<div class="solitude-tag tag-gallery-item gallery-item"><img class="nolazyload" src="/img/demo/generated/solitude-crystal-orbit.png" alt="Solitude 水晶轨道" loading="lazy"></div>

<div class="solitude-tag tag-gallery-item gallery-item"><img class="nolazyload" src="/img/demo/about/personality-enfj-v2.png" alt="ENFJ 性格主题图片" loading="lazy"></div>

<div class="solitude-tag tag-gallery-item gallery-item"><img class="nolazyload" src="/img/demo/about/personal-photo-selfie-wide.png" alt="宽幅生活照片" loading="lazy"></div>

<div class="solitude-tag tag-gallery-item gallery-item"><img class="nolazyload" src="/img/demo/about/game-apex-v1.webp" alt="游戏主题示例图片" loading="lazy"></div>

</div>

<figure class="solitude-tag tag-gallery-group gallery-group"><img class="gallery-group-img no-lightbox" src="/img/demo/cover-shortcodes-v2.webp" alt="Group Image Gallery"><figcaption><div class="gallery-group-name">图库分组</div><p>用于聚合同一主题下的一组图片。</p><a href="/"></a></figcaption></figure>

<h3 id="标签页">标签页</h3>
<p><code>tabs</code> 作为容器，每个 <code>tab</code> 提供标题和内容。为同一篇文章里的每组标签页设置唯一 <code>id</code>，可以避免状态互相影响。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; tabs id=&#34;demo-tabs&#34; &gt;}}
{{&lt; tab title=&#34;第一个&#34; &gt;}}第一个标签页{{&lt; /tab &gt;}}
{{&lt; tab title=&#34;第二个&#34; &gt;}}第二个标签页{{&lt; /tab &gt;}}
{{&lt; /tabs &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag tag-tabs tabs" id="demo-tabs" data-solitude-tabs><div class="tab-contents">
<section class="tab-item-content active" id="tab-0" data-tab-title="第一个" data-tab-icon="">第一个标签页</section>

<section class="tab-item-content" id="tab-1" data-tab-title="第二个" data-tab-icon="">第二个标签页</section>

<section class="tab-item-content" id="tab-2" data-tab-title="用于验证横向滚动的较长标签标题" data-tab-icon="">窄屏下标签导航可以横向滚动，并保留完整的键盘操作。</section>

</div></div>

<h3 id="时间线">时间线</h3>
<p>时间线由 <code>timeline</code> 和一个或多个 <code>timenode</code> 组成。时间与标题应保持简短，详细说明放在节点正文中。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; timeline title=&#34;迁移时间线&#34; &gt;}}
{{&lt; timenode time=&#34;2026-08-21&#34; title=&#34;Hugo 版本&#34; &gt;}}
完成原生主题迁移。
{{&lt; /timenode &gt;}}
{{&lt; /timeline &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag timeline tag-timeline "><div class="timeline-item headline"><div class="timeline-item-title"><div class="item-circle">迁移时间线</div></div></div>
<div class="timeline-item solitude-tag timenode tag-timenode"><div class="timeline-item-title meta"><div class="item-circle"><p>2026-08-21</p></div></div><div class="timeline-item-content body"><strong>Hugo 版本</strong>完成原生主题迁移。</div></div>

<div class="timeline-item solitude-tag timenode tag-timenode"><div class="timeline-item-title meta"><div class="item-circle"><p>2026-08-25</p></div></div><div class="timeline-item-content body"><strong>文档重组</strong>补充写法、参数与真实效果，让组件更容易检索和复用。</div></div>

</div>

<h3 id="系列文章与视频集合">系列文章与视频集合</h3>
<p><code>series</code> 会读取文章 Front Matter 中同名的 <code>series</code>，并按日期生成文章列表。<code>videos</code> 则把正文中的每行地址渲染为一个原生视频播放器。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; series name=&#34;官方示例&#34; &gt;}}

{{&lt; videos col=&#34;2&#34; &gt;}}
/media/shortcodes/flower.mp4
/media/shortcodes/friday.mp4
{{&lt; /videos &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<ol class="solitude-tag series-items tag-series"><li><a href="/p/shortcode-showcase.html" title="Solitude Hugo Shortcode 使用指南">Solitude Hugo Shortcode 使用指南</a></li></ol>

<div class="solitude-tag videos tag-videos" data-columns="2"><video controls preload="metadata"><source src="/media/shortcodes/flower.mp4"></video><video controls preload="metadata"><source src="/media/shortcodes/friday.mp4"></video></div>

<h3 id="聊天记录">聊天记录</h3>
<p><code>chat</code> 使用简洁的行文本语法展示对话：<code>{.名称}</code> 切换到右侧发送者，<code>{名称}</code> 切换到左侧发送者；随后直接写消息内容，连续内容用 <code>\\</code> 换行；<code>{:内容}</code> 是居中的系统提示（包括时间和撤回提示）。</p>
<figure class="code-block" data-code-block data-language="go-html-template">
  <figcaption class="code-block__toolbar">
    <span class="code-block__language">go-html-template</span>
      <button class="code-block__copy" type="button" data-code-copy>复制</button>
  </figcaption>
  <div class="code-block__viewport">
    <pre class="code-block__fallback" tabindex="0"><code class="language-go-html-template">{{&lt; chat &gt;}}
{:2024-11-09 23:39:30}
{.也许}
{.我们可以聊聊天}
{~克喵}
{.我还可以有名字}
{!克喵撤回了一条消息}
{用户 1}
{有趣}
{我学到了。}
{{&lt; /chat &gt;}}</code></pre>
  </div>
  <button class="code-block__expand" type="button" data-code-expand hidden>展开全部</button>
</figure>
<div class="solitude-tag chat" role="log" aria-label="聊天记录"><div class="chat-system">2024-11-09 23:39:30</div><div class="chat-body chat-myself">也许</div><div class="chat-body chat-myself">我们可以聊聊天</div><div class="chat-caption chat-myself">纸鹿</div><div class="chat-body chat-myself">我还可以有名字</div><div class="chat-system">纸鹿撤回了一条消息</div><div class="chat-caption">用户 1</div><div class="chat-body">有趣<br></div><div class="chat-body">我学到了。</div></div>

<ol>
<li>先用标准 Markdown 完成正文，只在标准语法无法表达时引入 shortcode。</li>
<li>一个组件解决一种内容关系，避免为了装饰而层层嵌套。</li>
<li>图片和媒体补全替代文本或标题，并优先选择稳定、可控的资源地址。</li>
<li>发布前执行完整构建，再在桌面端与移动端检查长标题、代码块、表格和交互组件。</li>
</ol>




  

<aside class="solitude-tag note success modern no-icon has-icon">
  <span class="note-icon" aria-hidden="true"><i class="fas fa-circle-check"></i></span>
  <div class="note-content">如果你正在迁移 Hexo 文章，可以先按组件名称替换旧标签，再对照本文逐项调整参数。这样比一次性改写整篇文章更容易定位构建错误。</div>
</aside>

]]></content><category term="内容组件" scheme="category"/><category term="官方示例" scheme="series"/><category term="Shortcode" scheme="tag"/><category term="Markdown" scheme="tag"/><category term="Hugo" scheme="tag"/></entry></feed>