<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hugo on dongxiaoqi's Blog</title><link>https://notion.dongxiaoqi.top/tags/hugo/</link><description>Recent content in Hugo on dongxiaoqi's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><copyright>CC BY-NC-SA 4.0</copyright><lastBuildDate>Thu, 13 Aug 2026 12:21:00 +0800</lastBuildDate><atom:link href="https://notion.dongxiaoqi.top/tags/hugo/index.xml" rel="self" type="application/rss+xml"/><item><title>Stack 主题个性化定制实录</title><link>https://notion.dongxiaoqi.top/p/stack-%E4%B8%BB%E9%A2%98%E4%B8%AA%E6%80%A7%E5%8C%96%E5%AE%9A%E5%88%B6%E5%AE%9E%E5%BD%95/</link><pubDate>Thu, 13 Aug 2026 11:12:00 +0800</pubDate><guid>https://notion.dongxiaoqi.top/p/stack-%E4%B8%BB%E9%A2%98%E4%B8%AA%E6%80%A7%E5%8C%96%E5%AE%9A%E5%88%B6%E5%AE%9E%E5%BD%95/</guid><description>&lt;h2 id="一背景"&gt;一、背景
&lt;/h2&gt;&lt;p&gt;Stack 主题切换上线后（见《博客主题从 MemE 切换到 Stack 实录》），博客外观与基础链路就绪。此后围绕头像、导航、视觉细节、字体、评论与社交做了一系列个性化定制，本文记录这些改动及其背后的取舍与踩坑。整个过程延续「无本地 hugo、直接靠 CI 验证」的工作方式，每个改动都是一次 push → 触发构建 → curl 线上确认的闭环。&lt;/p&gt;
&lt;h2 id="二改动清单"&gt;二、改动清单
&lt;/h2&gt;&lt;h3 id="1-博客头像"&gt;1. 博客头像
&lt;/h3&gt;&lt;p&gt;用户提供了一张《猫和老鼠》指挥家横图（1102×689）。Stack 侧边栏头像经 helper/image.html 的 .Resources.Get 解析，而 .site-logo 的 CSS 没有 object-fit（默认 fill 会拉伸），直接用横图会被拉变形。&lt;/p&gt;
&lt;p&gt;处理：用 Pillow 把原图中心裁成正方形 689×689，存 assets/img/avatar.jpeg，config 里 [params.sidebar] avatar = &amp;quot;img/avatar.jpeg&amp;quot;，原图备份为 avatar-source.jpeg。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;avatar-source.jpeg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;avatar.jpeg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;关键点：头像必须在 assets/ 下（Stack 用 Hugo Resources 解析，不是 static/），且文件扩展名要与实际文件一致，否则 .Resources.Get 匹配不到。&lt;/p&gt;
&lt;h3 id="2-分类菜单-404-修复"&gt;2. 分类菜单 404 修复
&lt;/h3&gt;&lt;p&gt;切换后点侧边栏「技术 / 随笔 / 关于」全跳 404。排查发现菜单 url 配的是 /categories/tech/（categoryMap 的小写英文 key），但 Notion Action 把文章的 Notion Category（中文 select 名「技术/随笔/关于」）原样写进 front matter 的 categories: 字段——categoryMap 只决定 content/zh 下的子目录名，不影响 front matter。Hugo 按 front matter 的 categories 生成分类页，实际路径是中文 /categories/技术/，与菜单对不上。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 实测验证&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl /categories/tech/ -&amp;gt; &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl /categories/技术/ -&amp;gt; &lt;span class="m"&gt;200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;修复：把菜单三个 url 改成 Hugo 实际生成的中文路径 /categories/技术/、/categories/随笔/、/categories/关于/。随笔暂无文章，/categories/随笔/ 仍 404，等有文章后自动出现，保留菜单项占位。&lt;/p&gt;
&lt;p&gt;教训：Notion→Hugo 链路里，分类页 URL 由 front matter 的 categories 决定，不由文件目录决定；改菜单前先 curl 确认 Hugo 实际生成的路径。&lt;/p&gt;
&lt;h3 id="3-页脚跳动的心"&gt;3. 页脚跳动的心
&lt;/h3&gt;&lt;p&gt;参考 guanqr.com，在版权行末尾加一颗 Font Awesome 实心心形，用 fa-heartbeat 双跳动画（1.3s 循环）。通过覆盖主题 partial 实现，不动 submodule：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;layouts/_partials/footer/footer.html：版权行追加 &lt;svg class="heart-icon"&gt;（FA 心形路径）&lt;/li&gt;
&lt;li&gt;layouts/_partials/footer/custom.html：注入心跳 @keyframes CSS（主题留空的扩展点）&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="k"&gt;keyframes&lt;/span&gt; &lt;span class="nt"&gt;heartbeat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;14&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;28&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;42&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;70&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;细节：心形红色 #ff4d4f，1em 尺寸随字号缩放，vertical-align 对齐基线；加 @media (prefers-reduced-motion: reduce) 守卫，系统开了「减少动态效果」时停止动画（无障碍）。&lt;/p&gt;
&lt;h3 id="4-字体中文霞鹜文楷--代码-jetbrains-mono"&gt;4. 字体：中文霞鹜文楷 + 代码 JetBrains Mono
&lt;/h3&gt;&lt;p&gt;目标是中文用霞鹜文楷、代码用 JetBrains Mono。采用混合方案：JetBrains Mono 走 Google Fonts CDN，霞鹜文楷只设 font-family 名走系统回退——用户本地装了才显示，省去几 MB webfont 的网络开销。&lt;/p&gt;
&lt;p&gt;Stack 主题的字体由三个 CSS 变量控制（在 variables.scss）：--base-font-family（界面）、--article-font-family（正文，继承 base）、--code-font-family（代码）。覆盖方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;layouts/_partials/head/custom-font.html：把加载的 Google Fonts 从 Lato 换成 JetBrains Mono&lt;/li&gt;
&lt;li&gt;assets/scss/custom.scss：重定义三个 CSS 变量&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;--base-font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;LXGW WenKai Screen&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;LXGW WenKai&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;霞鹜文楷&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apple-system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PingFang SC&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Microsoft YaHei&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;--article-font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;--code-font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;JetBrains Mono&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;LXGW WenKai Mono&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Menlo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Monaco&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Consolas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;monospace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;生效原理：style.scss 里 @import &amp;quot;custom.scss&amp;quot; 在 variables.scss 之后，我的 :root 重定义排在主题默认值之后，CSS 变量后者覆盖前者。霞鹜文楷回退链：LXGW WenKai Screen → LXGW WenKai → 霞鹜文楷 → 系统无衬线，未装则回退 PingFang SC / 微软雅黑。&lt;/p&gt;
&lt;p&gt;踩坑：custom.scss 是静态资源，不经过 Hugo 模板引擎，只能用 CSS 注释，不能写 {{}}（否则 SCSS 编译报错）。&lt;/p&gt;
&lt;h3 id="5-评论系统-giscus--社交链接"&gt;5. 评论系统 Giscus + 社交链接
&lt;/h3&gt;&lt;p&gt;评论选 Giscus（基于 GitHub Discussions，与 GitHub Pages 技术栈契合，免费无广告）。社交在原有 GitHub + RSS 基础上加 CSDN 和 Email。&lt;/p&gt;
&lt;p&gt;Giscus 需要 repo-id 和 category-id。这两个不必走 giscus.app 配置页，直接用 GitHub API 取：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启用 Discussions（REST PATCH）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X PATCH -H &lt;span class="s2"&gt;&amp;#34;Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://api.github.com/repos/vamViolet/notion-hugo-meme &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;has_discussions&amp;#34;: true}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 取 repo-id 和 category-id（GraphQL）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# query: repository(owner,name){ id, discussionCategories(first:20){ nodes{ id name slug } } }&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;拿到 repo-id R_kgDOTllGGw、Announcements 分类 id DIC_kwDOTllGG84DDR7I，写入 config [params.comments.giscus]。mapping=title 按标题关联 discussion，文章 URL 变了也不丢评论；lightTheme/darkTheme 跟随博客明暗主题。&lt;/p&gt;
&lt;p&gt;关键点：Stack 单篇文章的 comments front matter 字段会覆盖全局 [params.comments.enabled]。所以光开全局不够，还要把 archetype 和现有文章的 comments: false 全改成 true（9 篇批量 sed）。&lt;/p&gt;
&lt;p&gt;社交：Stack 侧边栏图标经 helper/icon.html 的 resources.GetMatch &amp;quot;icons/&lt;name&gt;.svg&amp;quot; 解析，主题内置图标没有 email/csdn，于是自己画了 assets/icons/email.svg（Tabler mail 风格）和 assets/icons/csdn.svg，在 [menu.social] 引用。&lt;/p&gt;
&lt;h2 id="三踩坑记录"&gt;三、踩坑记录
&lt;/h2&gt;&lt;h3 id="坑-1docker-action-生成文件的权限"&gt;坑 1：Docker Action 生成文件的权限
&lt;/h3&gt;&lt;p&gt;某次同步新文章，fix-tags 步骤报 PermissionError: [Errno 13] Permission denied。根因：rxrw/notion-blog 是 Docker action，在容器内以 root 生成 content/zh、static/images 文件，归 root 所有；后续 fix-tags / fix-dates 以 runner 用户运行，写或删这些文件就失败。这个潜在 bug 只有在需要改新文件时才暴露——只读的步骤会蒙混过去，所以前面几次构建一直没发现。&lt;/p&gt;
&lt;p&gt;修复：在 notion-blog 步骤之后、cleanup 之前加 chmod -R a+rwX content/zh static/images，一次性放开权限。&lt;/p&gt;
&lt;h3 id="坑-2notion-created_time-不可控迁移文章日期全变成今天"&gt;坑 2：Notion created_time 不可控，迁移文章日期全变成今天
&lt;/h3&gt;&lt;p&gt;迁移 9 篇 Gridea 老文章时，Notion Action 用页面 created_time 作为文章 date。但 created_time 是只读系统字段，API 创建时自动设为 now，无法覆盖。结果 2021/2023 的老文章同步后全变成今天的日期，堆在归档页顶部当「最新」。&lt;/p&gt;
&lt;p&gt;解法：加自愈 workflow 步骤——scripts/migrated-dates.json（title→原日期映射）+ scripts/fix-migrated-dates.py，每次 sync 在 fix-tags 之后、commit 之前重写匹配文章的 date/lastmod 回原日期。幂等，每次同步都跑，文件已在正确日期则不动。&lt;/p&gt;
&lt;h3 id="坑-3notion-链接必须是绝对-url"&gt;坑 3：Notion 链接必须是绝对 URL
&lt;/h3&gt;&lt;p&gt;创建 Notion 页面时，两篇文章 block append 报 Invalid URL for link。排查是源 HTML 里有相对锚点（#fn1 脚注、%E7%9B%AE%E5%BD%95 编码的「目录」TOC 链接）。Notion 的 link 字段只接受绝对 http(s) URL。修复：在转换器 text_seg 里加 valid_url 校验，非法链接保留文字、丢弃 link，避免阻断整批 block 写入。&lt;/p&gt;
&lt;h3 id="坑-4mybatisplus-图片-404"&gt;坑 4：mybatisplus 图片 404
&lt;/h3&gt;&lt;p&gt;2 张 mybatisplus 图片原图在 vamViolet.github.io/post-images/，Action 的 getImage 把文件存到 static/images/post-images/ 子目录时 os.Create 失败（子目录不存在），回退写出裸路径 /post-images/X.png 导致 404。解法：Hugo 把 static/ 全部映射到站点根，直接把图放到 static/post-images/X.png 即可让 /post-images/X.png 解析。文章 Status=Published 不会再被 Action 覆盖，此补丁持久。&lt;/p&gt;
&lt;h2 id="四验证方法"&gt;四、验证方法
&lt;/h2&gt;&lt;p&gt;全程无本地 hugo，靠 CI 验证：改完 push → workflow_dispatch 触发 → 轮询 run 状态 → 成功后 curl 线上页面抓 HTML/CSS 确认元素和变量生效。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 触发构建（用 git credential 里的 token，无需 gh CLI）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;protocol=https\nhost=github.com\n\n&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; git credential fill &lt;span class="p"&gt;|&lt;/span&gt; sed -n &lt;span class="s2"&gt;&amp;#34;s/^password=//p&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X POST -H &lt;span class="s2"&gt;&amp;#34;Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://api.github.com/repos/vamViolet/notion-hugo-meme/actions/workflows/notion-blog.yml/dispatches &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;ref&amp;#34;:&amp;#34;master&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 验证字体变量在编译后 CSS 里（minify 后有两个 :root 定义，后者覆盖前者）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl https://notion.dongxiaoqi.top/scss/style.min.&amp;lt;hash&amp;gt;.css &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s1"&gt;&amp;#39;JetBrains Mono&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="五最终效果"&gt;五、最终效果
&lt;/h2&gt;&lt;p&gt;线上 &lt;a class="link" href="https://notion.dongxiaoqi.top/" target="_blank" rel="noopener"
 &gt;https://notion.dongxiaoqi.top/&lt;/a&gt; 已确认：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;侧边栏头像（Tom &amp;amp; Jerry 指挥家，正方形裁剪不拉伸）&lt;/li&gt;
&lt;li&gt;技术 / 关于 菜单可正常打开（中文分类页），随笔待文章&lt;/li&gt;
&lt;li&gt;页脚版权行末尾跳动的心（红色，1.3s 双跳）&lt;/li&gt;
&lt;li&gt;中文霞鹜文楷（系统装了才显示）、代码 JetBrains Mono&lt;/li&gt;
&lt;li&gt;文章页 Giscus 评论框（参数齐全，待装 App）、侧边栏 CSDN / Email / GitHub / RSS 四图标&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六遗留事项"&gt;六、遗留事项
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Giscus App 待手动安装：https://github.com/apps/giscus → Install → 授权 notion-hugo-meme 仓库，否则评论框报错&lt;/li&gt;
&lt;li&gt;Notion token 在对话历史明文出现过，建议轮换并更新 GitHub NOTION_TOKEN secret&lt;/li&gt;
&lt;li&gt;随笔分类待补文章，/categories/随笔/ 目前 404&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>博客主题从 MemE 切换到 Stack 实录</title><link>https://notion.dongxiaoqi.top/p/%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98%E4%BB%8E-meme-%E5%88%87%E6%8D%A2%E5%88%B0-stack-%E5%AE%9E%E5%BD%95/</link><pubDate>Wed, 12 Aug 2026 12:45:00 +0800</pubDate><guid>https://notion.dongxiaoqi.top/p/%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98%E4%BB%8E-meme-%E5%88%87%E6%8D%A2%E5%88%B0-stack-%E5%AE%9E%E5%BD%95/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;一次完整的话题切换实操记录：从 MemE 换到 hugo-theme-stack，顺带把被钉死的 Hugo 老版本解锁。包含三个真实踩坑和 CI 迭代验证过程。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一背景"&gt;一、背景
&lt;/h2&gt;&lt;p&gt;博客原本用 MemE 主题（git submodule，钉在 2022 年的 v5.0.0）。MemE v5.0.0 用了旧版 &lt;code&gt;resources.ToCSS&lt;/code&gt; API，与新版 Hugo 不兼容，导致 CI 工作流被迫把 Hugo 钉在 &lt;code&gt;0.112.7&lt;/code&gt;——这是个 2023 年的老版本，越来越难维护，新特性也用不了。&lt;/p&gt;
&lt;p&gt;目标：换成更现代的主题，并顺带解除旧 Hugo 版本锁。&lt;/p&gt;
&lt;h2 id="二选型"&gt;二、选型
&lt;/h2&gt;&lt;p&gt;候选了三个主流主题，最终选 &lt;strong&gt;hugo-theme-stack&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;卡片式文章列表、左侧边栏、原生暗色模式切换&lt;/li&gt;
&lt;li&gt;维护活跃，文档完善&lt;/li&gt;
&lt;li&gt;要求 Hugo ≥ 0.157.0 extended，正好顺带升级&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三改动清单"&gt;三、改动清单
&lt;/h2&gt;&lt;h3 id="1-替换主题-submodule"&gt;1. 替换主题 submodule
&lt;/h3&gt;&lt;p&gt;移除 MemE，新增 Stack 并锁定到稳定 tag：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule deinit -f themes/meme
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git rm -f themes/meme
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf .git/modules/themes/meme
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule add -b master https://github.com/CaiJimmy/hugo-theme-stack.git themes/stack
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git -C themes/stack checkout v4.0.3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="2-重写-configtoml"&gt;2. 重写 config.toml
&lt;/h3&gt;&lt;p&gt;从 1432 行的 MemE 配置精简到约 210 行。关键调整：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;theme = &amp;quot;stack&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mainSections = [&amp;quot;zh&amp;quot;]&lt;/code&gt;：核心，让首页读 &lt;code&gt;content/zh/&lt;/code&gt;（Notion Action 同步目录，不改 Action 也不改清理脚本）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[permalinks] zh = &amp;quot;/p/:slug/&amp;quot;&lt;/code&gt;：用 Stack 默认 URL 风格，文章 URL 从 &lt;code&gt;/zh/xxx/&lt;/code&gt; 变 &lt;code&gt;/p/xxx/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[menu]&lt;/code&gt; 改成 Stack 的 &lt;code&gt;main&lt;/code&gt; + &lt;code&gt;social&lt;/code&gt; 格式&lt;/li&gt;
&lt;li&gt;删除 MemE 专属的 &lt;code&gt;[params]&lt;/code&gt;、&lt;code&gt;[outputFormats]&lt;/code&gt;、&lt;code&gt;[outputs]&lt;/code&gt; 等几百行&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-重写-archetypesnotionmd"&gt;3. 重写 archetypes/notion.md
&lt;/h3&gt;&lt;p&gt;Notion Action 同步时套这个模板。改成 Stack 的 front matter 字段，两个关键点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;draft: false&lt;/code&gt;：Stack 默认 archetype 是 &lt;code&gt;draft: true&lt;/code&gt;，不显式改 false 的话同步出的文章会被当草稿隐藏&lt;/li&gt;
&lt;li&gt;&lt;code&gt;category&lt;/code&gt; → &lt;code&gt;categories&lt;/code&gt;（复数）：Stack 模板用 &lt;code&gt;.Params.categories&lt;/code&gt; 判断分类，单数 key 不会显示分类徽章&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-升级-hugo"&gt;4. 升级 Hugo
&lt;/h3&gt;&lt;p&gt;工作流里 &lt;code&gt;0.112.7&lt;/code&gt; → &lt;code&gt;0.163.3&lt;/code&gt;，&lt;code&gt;extended: true&lt;/code&gt; 保留。&lt;/p&gt;
&lt;h2 id="四踩坑记录"&gt;四、踩坑记录
&lt;/h2&gt;&lt;p&gt;整个过程走了三轮 CI 迭代，每个坑都是一次失败构建。&lt;/p&gt;
&lt;h3 id="坑-1计划里的-hugo-01572-根本不存在"&gt;坑 1：计划里的 Hugo 0.157.2 根本不存在
&lt;/h3&gt;&lt;p&gt;第一轮按计划填 &lt;code&gt;hugo-version: '0.157.2'&lt;/code&gt;，&lt;code&gt;peaceiris/actions-hugo&lt;/code&gt; 直接报错：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Unable to find a compatible Hugo release asset for this runner.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;查 Hugo releases 才发现：0.157 线&lt;strong&gt;只有 0.157.0&lt;/strong&gt;，之后直接跳到 0.160+，根本不存在 0.157.1/0.157.2。改成实际存在的 &lt;code&gt;0.163.3&lt;/code&gt;（成熟 .3 补丁版本，远高于 Stack 的 min 0.157.0）解决。&lt;/p&gt;
&lt;p&gt;教训：版本号要查 releases 确认存在，别想当然填补丁号。&lt;/p&gt;
&lt;h3 id="坑-2菜单图标不在-stack-内置集"&gt;坑 2：菜单图标不在 Stack 内置集
&lt;/h3&gt;&lt;p&gt;第二轮 Hugo 装上了，但构建报：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR Error: icon &amp;#39;code.svg&amp;#39; is not found under &amp;#39;assets/icons&amp;#39; folder
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR Error: icon &amp;#39;notes.svg&amp;#39; is not found under &amp;#39;assets/icons&amp;#39; folder
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;菜单里 &lt;code&gt;技术&lt;/code&gt; 用了 &lt;code&gt;icon = &amp;quot;code&amp;quot;&lt;/code&gt;、&lt;code&gt;随笔&lt;/code&gt; 用了 &lt;code&gt;icon = &amp;quot;notes&amp;quot;&lt;/code&gt;，但 Stack 只内置 24 个 SVG（&lt;code&gt;themes/stack/assets/icons/&lt;/code&gt;），不含 code/notes。改成内置图标：技术→&lt;code&gt;categories&lt;/code&gt;、随笔→&lt;code&gt;archives&lt;/code&gt;、关于→&lt;code&gt;user&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;教训：主题里引用的资源（图标、图片）要先确认主题是否自带，没有就得自己往 &lt;code&gt;assets/&lt;/code&gt; 放。&lt;/p&gt;
&lt;h3 id="坑-3languagecode-弃用警告"&gt;坑 3：languageCode 弃用警告
&lt;/h3&gt;&lt;p&gt;第三轮构建成功，但有 WARN：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WARN deprecated: project config key languageCode was deprecated in Hugo v0.158.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;修这个又踩了一层：顶层 &lt;code&gt;languageCode&lt;/code&gt; 在 0.158 弃用，移到 &lt;code&gt;[languages.zh].languageCode&lt;/code&gt; 后，0.163 又把这个键改名为 &lt;code&gt;locale&lt;/code&gt;（连同 &lt;code&gt;languageName&lt;/code&gt; → &lt;code&gt;label&lt;/code&gt;）。最终用最新键名：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zh&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;zh-CN&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;中文&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;额外风险：显式加 &lt;code&gt;[languages.zh]&lt;/code&gt; 后，Hugo 可能把 &lt;code&gt;content/zh/&lt;/code&gt; 当成 zh 语言根目录（而非 section），导致 &lt;code&gt;mainSections=[&amp;quot;zh&amp;quot;]&lt;/code&gt; 失配、首页变空。本地用下载的 hugo 二进制构建验证过：仍是 section，首页 2 篇文章、&lt;code&gt;/p/&lt;/code&gt; URL 都没变，才敢推 CI。&lt;/p&gt;
&lt;h2 id="五验证方法"&gt;五、验证方法
&lt;/h2&gt;&lt;p&gt;这次没用本地 &lt;code&gt;hugo server&lt;/code&gt; 预览，直接靠 CI 验证：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git push&lt;/code&gt; 后用 GitHub API 手动触发 &lt;code&gt;workflow_dispatch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;轮询 run 状态到 completed&lt;/li&gt;
&lt;li&gt;失败就下载日志 zip，定位报错步骤，修复重推&lt;/li&gt;
&lt;li&gt;成功后抓线上首页 HTML，核对 Stack 标记、文章链接、CSS/JS 资源是否 200&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三轮迭代，每轮约 2–3 分钟，比反复起本地服务更快也更接近真实部署环境。&lt;/p&gt;
&lt;h2 id="六最终效果"&gt;六、最终效果
&lt;/h2&gt;&lt;p&gt;线上 &lt;a class="link" href="https://notion.dongxiaoqi.top/" target="_blank" rel="noopener"
 &gt;https://notion.dongxiaoqi.top/&lt;/a&gt; 已确认：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stack 外观：左侧边栏、卡片式文章列表、暗色模式切换&lt;/li&gt;
&lt;li&gt;首页正常显示 2 篇文章，URL 是 &lt;code&gt;/p/xxx/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;文章页正文、标题、代码块、标签、阅读时长都正常&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/tags/&lt;/code&gt; 三个标签（Hugo / Notion / GitHub-Pages）正常&lt;/li&gt;
&lt;li&gt;CSS（55KB）/ JS（8KB）资源都 200，无样式崩坏&lt;/li&gt;
&lt;li&gt;旧 &lt;code&gt;/zh/xxx/&lt;/code&gt; URL 已 404（符合预期，文章少无外链，可接受）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="七语言切换器的实现"&gt;七、语言切换器的实现
&lt;/h2&gt;&lt;p&gt;主题切换上线后，照着 demo 站（demo.stack.cai.im）加了侧边栏的语言切换下拉框。这一节记录实现机制和一个非标准目录结构下踩的坑。&lt;/p&gt;
&lt;h3 id="机制hugoismultilingual"&gt;机制：hugo.IsMultilingual
&lt;/h3&gt;&lt;p&gt;Stack 的切换器在 themes/stack/layouts/_partials/sidebar/left.html，是一个 &lt;select&gt; 下拉框，遍历 .Site.Home.AllTranslations 生成 option，每个指向对应语言首页 URL、label 用 .Language.Label。但它被包在一个前置条件里：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hugo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsMultilingual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;i18n-switch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;也就是说，只有 Hugo 处于多语言模式（[languages] 里定义了 ≥2 种语言）时切换器才渲染。demo 站每种语言都有真实翻译内容，多语言模式天然开启，切换器自然出现。单语博客要显示它，就得显式加第二种语言。&lt;/p&gt;
&lt;h3 id="坑contentzh-当-section-用contenten-进不了英语语言"&gt;坑：content/zh 当 section 用，content/en 进不了英语语言
&lt;/h3&gt;&lt;p&gt;本站的内容目录结构是非标准的：文章在 content/zh/，靠 mainSections=[&amp;quot;zh&amp;quot;] + permalinks zh=&amp;quot;/p/:slug/&amp;quot; 让首页读到它、文章落在 /p/。这是为了不动 Notion Action 硬编码的 contentFolder。&lt;/p&gt;
&lt;p&gt;加第二种语言时本能地想建 content/en/ 放英语内容——但本地 hugo 实测发现行不通：默认语言 zh 且 defaultContentLanguageInSubdir=false 时，Hugo 从 content/ 根扫描，把 content/ 下所有子目录（含 content/en/）都当成 zh 的 section。结果 content/en/ 永远成不了英语语言根，英语首页 RegularPages=0，空列表。&lt;/p&gt;
&lt;p&gt;换成 defaultContentLanguageInSubdir=true 也没用，content/en/ 依旧被默认语言吞成 section（变成 /zh/en/posts/...）。这个坑用调试 partial 打印 .Site.RegularPages 的 type/url 才定位到。&lt;/p&gt;
&lt;h3 id="解法by-filename-后缀-enmd"&gt;解法：by-filename 后缀 .en.md
&lt;/h3&gt;&lt;p&gt;改用 Hugo 的 by-filename 机制：文件名带 .&lt;lang&gt;.md 后缀的会归对应语言，且继承所在目录的 section。英文欢迎页放在 content/zh/welcome.en.md——.en 后缀让它归英语语言，content/zh/ 目录让它共享 section &amp;quot;zh&amp;quot;，于是 mainSections 和 permalinks 完全不用改。&lt;/p&gt;
&lt;p&gt;效果：中文文章仍在 /p/:slug/（URL 零变化），英文欢迎页在 /en/p/welcome/，切换器选项 中文(/) ↔ English(/en/)。&lt;/p&gt;
&lt;h3 id="配套改动"&gt;配套改动
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;config.toml 加 [languages.en]（locale=&amp;quot;en-US&amp;quot;, label=&amp;quot;English&amp;quot;, weight=2），开启 IsMultilingual，切换器自动渲染。&lt;/li&gt;
&lt;li&gt;新建 content/zh/welcome.en.md：英文欢迎页，说明本站主语言为中文、英文版建设中，附返回中文首页的链接。&lt;/li&gt;
&lt;li&gt;工作流清理脚本加 TRANSLATION_SUFFIXES=(&amp;quot;.en.md&amp;quot;,) 跳过翻译文件——否则每次 CI 会 git rm 掉欢迎页（Notion Action 不产生 .en.md，它不在 expected 集合里）。已实测：found 2 .md file(s); 0 to delete，欢迎页安全。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="后续加英文内容"&gt;后续加英文内容
&lt;/h3&gt;&lt;p&gt;想加英文文章，按同样规则放 content/zh/&lt;name&gt;.en.md 即可，自动出现在 /en/ 列表、URL 为 /en/p/&lt;name&gt;/。若英文文章多了，建议重新评估是否把 Notion 同步改成真正的多语言结构（那是另一个项目）。&lt;/p&gt;
&lt;h2 id="八遗留事项"&gt;八、遗留事项
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分类徽章不显示&lt;/strong&gt;：现有两篇文章 front matter 是 &lt;code&gt;category: 首页&lt;/code&gt;（单数 key），Stack 读 &lt;code&gt;categories&lt;/code&gt;（复数）。新 archetype 已改复数，下次 Notion 重新同步时自动修好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion token 安全&lt;/strong&gt;：集成 token 曾在对话中明文出现，建议去 Notion 重新生成并更新 GitHub 仓库的 &lt;code&gt;NOTION_TOKEN&lt;/code&gt; secret。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="九关键命令速查"&gt;九、关键命令速查
&lt;/h2&gt;&lt;p&gt;触发 CI 构建（用仓库存储的 GitHub 凭据，无需 gh CLI）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 取 git credential 里的 token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;protocol=https\nhost=github.com\n\n&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; git credential fill &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^password=&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/^password=//&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 手动触发 workflow&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X POST -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;ref&amp;#34;:&amp;#34;master&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://api.github.com/repos/vamViolet/notion-hugo-meme/actions/workflows/notion-blog.yml/dispatches
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;下载某次 run 的日志（API 返回 302 到 S3，要跟跳转）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;REDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -D - -o /dev/null -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://api.github.com/repos/vamViolet/notion-hugo-meme/actions/runs/&amp;lt;RUN_ID&amp;gt;/logs &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -i &lt;span class="s1"&gt;&amp;#39;^location:&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/^[Ll]ocation: //&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -o logs.zip &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$REDIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unzip logs.zip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>notion-hugo-meme 操作手册</title><link>https://notion.dongxiaoqi.top/p/notion-hugo-meme-%E6%93%8D%E4%BD%9C%E6%89%8B%E5%86%8C/</link><pubDate>Wed, 29 Jul 2026 03:05:00 +0800</pubDate><guid>https://notion.dongxiaoqi.top/p/notion-hugo-meme-%E6%93%8D%E4%BD%9C%E6%89%8B%E5%86%8C/</guid><description>&lt;h1 id="notion-hugo-meme-操作手册"&gt;notion-hugo-meme 操作手册
&lt;/h1&gt;&lt;p&gt;本项目把 Notion 数据库作为内容源，通过 GitHub Actions 自动同步为 Markdown，再用 Hugo 构建成静态博客并部署到 GitHub Pages。本文档梳理项目结构，并给出从「写文章」到「上线/下线」的完整操作流程。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;仓库地址：https://github.com/vamViolet/notion-hugo-meme 博客地址：https://notion.dongxiaoqi.top/&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="一整体架构"&gt;一、整体架构
&lt;/h2&gt;&lt;p&gt;数据流是单向的、全自动的（每 2 小时触发一次，也可手动触发）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Notion 数据库 ──(rxrw/notion-blog Action)──&amp;gt; content/zh/*.md ──(Hugo build)──&amp;gt; GitHub Pages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ 把 Status=Finished 的文章拉成 md └─ https://notion.dongxiaoqi.top/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ 同步成功后把 Status 改成 Published
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ 清理步骤：删除已下线文章的 md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;三个关键角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Notion 数据库&lt;/strong&gt;：唯一的内容编辑入口。每篇文章是一条记录，&lt;code&gt;Status&lt;/code&gt; 控制是否上线。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub 仓库&lt;/strong&gt;：存放 Hugo 站点源码、同步出来的 md、以及自动化工作流。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Pages&lt;/strong&gt;：托管构建产物，对外提供博客访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二项目结构"&gt;二、项目结构
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;notion-hugo-meme/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── .github/workflows/notion-blog.yml # 核心：同步 + 清理 + 构建 + 部署 的工作流
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── config.toml # Hugo 站点配置（站名、域名、主题、菜单等）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── notionblog.config.json # notion-blog Action 的配置（数据库 ID、字段映射、过滤规则）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── archetypes/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── default.md # `hugo new` 默认模板
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── notion.md # Notion 同步时套用的 front matter 模板
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── content/zh/ # 同步出来的文章 md（按 Category 分子目录）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 建筑服务能力开发.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── static/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── CNAME # 自定义域名（notion.dongxiaoqi.top）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── images/ # 文章图片（Action 自动下载到这里）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── themes/meme/ # MemE 主题（git submodule，指向 rxrw/hugo-theme-meme）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── resources/ # Hugo 构建缓存
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── README.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="关键配置文件"&gt;关键配置文件
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;notionblog.config.json&lt;/code&gt;&lt;/strong&gt; —— 决定 Action 怎么从 Notion 拉文章：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;字段&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;filterProp&lt;/code&gt; / &lt;code&gt;filterValue&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;只同步 &lt;code&gt;Status&lt;/code&gt; 为 &lt;code&gt;Finished&lt;/code&gt; 的文章&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;publishedValue&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;同步成功后把 Status 改成 &lt;code&gt;Published&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;propertyCategories&lt;/code&gt; / &lt;code&gt;categoryMap&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Category&lt;/code&gt; 字段映射：技术→tech、随笔→essay、关于→about，首页→根目录&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;contentFolder&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;同步到的目录：&lt;code&gt;content/zh&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;imagesFolder&lt;/code&gt; / &lt;code&gt;imagesLink&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;图片下载到 &lt;code&gt;static/images/&lt;/code&gt;，链接前缀 &lt;code&gt;/images&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;config.toml&lt;/code&gt;&lt;/strong&gt; —— Hugo 站点配置要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;baseURL = &amp;quot;https://notion.dongxiaoqi.top/&amp;quot;&lt;/code&gt;：自定义域名，构建时不能用 github.io URL 覆盖，否则内链全 404。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;title = &amp;quot;dongxiaoqi's Blog&amp;quot;&lt;/code&gt;：站点名。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;theme = &amp;quot;meme&amp;quot;&lt;/code&gt;：使用 MemE 主题（submodule，v5.0.0，2022 年版）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.github/workflows/notion-blog.yml&lt;/code&gt;&lt;/strong&gt; —— 两个 Job：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;auto-sync-from-notion-to-github&lt;/code&gt;：checkout → 跑 notion-blog Action 拉文章 → 清理已下线文章 → 提交推送。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build-and-deploy&lt;/code&gt;：拉最新提交 → Hugo 0.112.7 extended 构建 → 部署到 GitHub Pages。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="三notion-数据库字段"&gt;三、Notion 数据库字段
&lt;/h2&gt;&lt;p&gt;每篇文章（一条记录）需要这些属性：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;属性&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Status&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;状态（status）&lt;/td&gt;
					&lt;td&gt;控制上线：&lt;code&gt;Finished&lt;/code&gt;/&lt;code&gt;Published&lt;/code&gt; = 在线，其余 = 下线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Category&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;单选（select）&lt;/td&gt;
					&lt;td&gt;分类目录：&lt;code&gt;首页&lt;/code&gt;/&lt;code&gt;技术&lt;/code&gt;/&lt;code&gt;随笔&lt;/code&gt;/&lt;code&gt;关于&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Tags&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;多选（multi_select）&lt;/td&gt;
					&lt;td&gt;标签&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Created by&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;创建者（created_by）&lt;/td&gt;
					&lt;td&gt;Action 读取作者名（硬编码依赖，缺了会报错）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="status-状态机"&gt;Status 状态机
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Status&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
					&lt;th&gt;博客上是否可见&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;In progress&lt;/code&gt;（进行中）&lt;/td&gt;
					&lt;td&gt;写到一半&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Finished&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;写完待发布 → 下次同步会拉取并上线&lt;/td&gt;
					&lt;td&gt;是（同步后）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Published&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;已上线（同步后 Action 自动置为此状态）&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;Offline&lt;/code&gt;（已下线）&lt;/td&gt;
					&lt;td&gt;主动下线 → 清理步骤会删掉对应 md&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;p&gt;注意：博客是纯静态站点，没有登录鉴权，所以「私密」等价于「下线」——只要 Status 不是 Finished/Published，文章就不会出现在博客上。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="四日常操作"&gt;四、日常操作
&lt;/h2&gt;&lt;h3 id="41-发布一篇新文章"&gt;4.1 发布一篇新文章
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;在 Notion 数据库里 &lt;strong&gt;New&lt;/strong&gt; 一条记录，填好 &lt;code&gt;Name&lt;/code&gt;（标题）、&lt;code&gt;Category&lt;/code&gt;、&lt;code&gt;Tags&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在正文里写内容（支持 Markdown 风格、代码块、表格、图片）。&lt;/li&gt;
&lt;li&gt;把 &lt;code&gt;Status&lt;/code&gt; 设为 &lt;strong&gt;&lt;code&gt;Finished&lt;/code&gt;&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;等待下次 workflow 触发（最多 2 小时），或去 GitHub 仓库 Actions 页面手动 &lt;code&gt;Run workflow&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;同步成功后，文章出现在博客，Status 自动变成 &lt;code&gt;Published&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="42-修改已发布文章"&gt;4.2 修改已发布文章
&lt;/h3&gt;&lt;p&gt;直接在 Notion 改正文/标题/分类，保持 &lt;code&gt;Status&lt;/code&gt; 为 &lt;code&gt;Finished&lt;/code&gt; 或 &lt;code&gt;Published&lt;/code&gt;，下次同步会更新对应 md。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;想立即触发同步，又不想等 2 小时：GitHub 仓库 → Actions → &lt;code&gt;notion-blog&lt;/code&gt; → &lt;code&gt;Run workflow&lt;/code&gt;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="43-下线一篇文章"&gt;4.3 下线一篇文章
&lt;/h3&gt;&lt;p&gt;把 &lt;code&gt;Status&lt;/code&gt; 从 &lt;code&gt;Finished&lt;/code&gt;/&lt;code&gt;Published&lt;/code&gt; 改成 &lt;strong&gt;&lt;code&gt;Offline&lt;/code&gt;&lt;/strong&gt;（或 &lt;code&gt;Todo&lt;/code&gt;/&lt;code&gt;In progress&lt;/code&gt;）即可。下次 run 的清理步骤会自动 &lt;code&gt;git rm&lt;/code&gt; 掉对应 md，文章从博客消失。&lt;/p&gt;
&lt;h3 id="44-改分类--改标题"&gt;4.4 改分类 / 改标题
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;改分类&lt;/strong&gt;：在 Notion 改 &lt;code&gt;Category&lt;/code&gt;。注意：旧分类目录下的旧 md 不会自动删除，需手动清理或等清理步骤处理（清理是按「当前 Notion 里 Finished/Published 的文章」对账的）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;改标题&lt;/strong&gt;：会生成新文件名的 md，旧文件名的 md 会成为孤儿，下次清理步骤会自动删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="五首次部署--排错清单"&gt;五、首次部署 / 排错清单
&lt;/h2&gt;&lt;p&gt;如果同步或部署出问题，按这个顺序排查：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Notion 数据库是否关联了 Integration&lt;/strong&gt;：数据库右上角 &lt;code&gt;...&lt;/code&gt; → &lt;code&gt;Connections&lt;/code&gt; → 添加你创建的 Integration。没关联会 404。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Secret 是否正确&lt;/strong&gt;：仓库 Settings → Secrets and variables → Actions，需有 &lt;code&gt;NOTION_TOKEN&lt;/code&gt;（值是 Notion Integration token，&lt;code&gt;ntn_&lt;/code&gt; 开头）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion 字段是否齐全&lt;/strong&gt;：&lt;code&gt;Name&lt;/code&gt;/&lt;code&gt;Status&lt;/code&gt;/&lt;code&gt;Category&lt;/code&gt;/&lt;code&gt;Created by&lt;/code&gt; 必须存在且类型正确，缺了 Action 会报错（但 Action 会吞掉错误、显示成功，要看 Actions 日志才能发现）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Pages 源是否设为 Actions&lt;/strong&gt;：仓库 Settings → Pages → Source 选 &lt;code&gt;GitHub Actions&lt;/code&gt;（不是 gh-pages 分支）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;域名/CNAME&lt;/strong&gt;：&lt;code&gt;static/CNAME&lt;/code&gt; 必须是裸域名 &lt;code&gt;notion.dongxiaoqi.top&lt;/code&gt;，不能带 &lt;code&gt;http://&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hugo 版本&lt;/strong&gt;：工作流固定用 &lt;code&gt;0.112.7 extended&lt;/code&gt;。MemE v5.0.0 与新版 Hugo 的 &lt;code&gt;resources.ToCSS&lt;/code&gt; 不兼容，&lt;strong&gt;不要升到 latest&lt;/strong&gt;，除非先升主题 submodule。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="六已知限制"&gt;六、已知限制
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Action 只增不删&lt;/strong&gt;：rxrw/notion-blog 只会新增/更新 md，不会删除。下线靠本仓库自加的清理步骤实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正文只取前 100 个 block&lt;/strong&gt;：Action 不做 block 分页，超长文章（&amp;gt;100 个 Notion block）会被截断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误被吞&lt;/strong&gt;：Action 内部出错只 &lt;code&gt;log.Println&lt;/code&gt; 后 &lt;code&gt;exit 0&lt;/code&gt;，永远显示「成功」。排查要看 Actions 的完整日志。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;属性名硬编码&lt;/strong&gt;：Action 代码里写死了 &lt;code&gt;Name&lt;/code&gt;/&lt;code&gt;Category&lt;/code&gt;/&lt;code&gt;Created by&lt;/code&gt; 等英文字段名，改不了。&lt;/li&gt;
&lt;li&gt;**Tags 渲染缺陷：**rxrw/notion-blog 用 &lt;strong&gt;tags : {{.Tags}}&lt;/strong&gt; 渲染多选标签，Go 切片默认输出 &lt;strong&gt;[a b c]&lt;/strong&gt;（空格分隔无逗号），Hugo 会当成一个名为 “a b c” 的畸形标签。本仓库工作流加了 Fix tags front-matter format 步骤，同步后自动改成逗号分隔 &lt;strong&gt;[a, b, c]&lt;/strong&gt;，博客 /tags/ 页和文章页才能正确显示多个独立标签。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag 命名约束：&lt;strong&gt;Notion 的 tag 名&lt;/strong&gt;不要含空格&lt;/strong&gt;（如用 GitHub-Pages 而非 GitHub Pages）。Action 输出端是空格分隔，含空格的标签名无法无损还原，会被错误拆成多个。中文标签不受影响（如 生产力）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="七相关链接"&gt;七、相关链接
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;仓库：https://github.com/vamViolet/notion-hugo-meme&lt;/li&gt;
&lt;li&gt;博客：https://notion.dongxiaoqi.top/&lt;/li&gt;
&lt;li&gt;主题：https://github.com/rxrw/hugo-theme-meme&lt;/li&gt;
&lt;li&gt;Action：https://github.com/rxrw/notion-blog&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>