起因
第一章搭好的博客是扁平的时间线——所有文章都在 content/posts/ 下,按时间倒序排列。这种结构很适合写日记或杂记,但是想要写长篇连载(比如复健笔记、菜谱、相机使用说明书)就会发现:
- 同一系列的文章会被时间打散
- 读者点进单篇看不到上下文,不知道还有别的章节
- 我自己也容易忘了之前写到哪
所以我想加一个书架放在主页最上方,和"杂记"并列,每本书内部有章、节两层结构。
整体方案
Claude 看完 dream 主题的源码之后给出的方案是:
Hugo 自带 page bundle 结构能完美表达"书 → 章 → 节"三层关系。书是一个 branch bundle(带
_index.md的目录),章是嵌套在书目录下的 branch bundle,节是章目录下的普通.md文件。
具体的内容目录:
content/books/
├── _index.md (书架根,渲染时跳过)
├── rehab/ (一本书:复健笔记)
│ ├── _index.md
│ ├── chapter-01/
│ │ ├── _index.md (章简介)
│ │ ├── section-01.md
│ │ └── section-02.md
│ └── chapter-02/
└── blog/ (也可以"平结构"——章本身就是节)
├── _index.md
├── chapter-01.md (没有节,章就是叶节点)
└── chapter-02.md
自定义 book CSS 和 JS
因为 Hugo Dream 模板没有书架,所以需要Claude搓一个新的格式。
Claude 的解决方案是:
自己写一个
static/css/book.css,在hugo.toml的[params.advanced]里通过customCSS加载。所有书架相关的样式(侧栏粘性、归档时间线、卡片样式、暗色模式微调、tooltip)都写进这一个文件。
book.css 最终大概 500 行,覆盖:
- 书侧栏 sticky 行为 + 暗色模式背景调整
- 首页书卡片 grid 布局 + 帖子卡片
- /posts/ 归档按"年 → 月"两层分组
- nav 桌面悬浮 tooltip(
::after+attr(title)) - Waline 评论框布局微调
- Mastodon 评论区样式
JS 只写了一个:static/js/book-scrollspy.js。节阅读时右侧的 TOC 会跟随滚动高亮当前 H2/H3,用 IntersectionObserver 实现,约 60 行。
修复顶部 nav:sticky → fixed
dream 主题的 <nav> 用的是 position: sticky。本地预览没问题,但部署到线上后我发现往下滚几下 nav 就消失了。Claude 排查后说:
主题的
.flip-container有一个写死的height: calc(100vh - 80px - 2rem)打破了 sticky 的滚动上下文。把 nav 改成position: fixed,然后给 body 加一个padding-top可以修复。
最终 CSS:
body > nav {
position: fixed !important;
top: 0; left: 0; right: 0;
z-index: 40;
background-color: oklch(var(--b1));
border-bottom: 1px solid oklch(var(--bc) / 0.12);
}
body { padding-top: 5rem; }
@media (min-width: 1024px) {
body { padding-top: 6rem; }
}
修复颜色闪烁问题
日间模式下,每次切换页面会先黑一闪再变白。Claude 解释:
系统在暗色模式时,浏览器在 JS 加载完之前默认背景是黑色,然后 Alpine.js(defer 加载)才把网页切到 emerald(亮色),出现"黑一下→白"的闪烁。修法是在
<head>顶部加一段同步执行的 inline script,比 Alpine 早一步把 class 和 data-theme 设到<html>上。
覆盖 layouts/partials/head.html,在文件开头加:
<script>
(function() {
var pref = localStorage.getItem('hugo-theme-dream-is-dark');
var prefersDark = matchMedia('(prefers-color-scheme: dark)').matches;
var isDark = pref === 'y' || (pref !== 'n' && prefersDark);
document.documentElement.classList.add(isDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', isDark ? 'forest' : 'emerald');
document.documentElement.style.backgroundColor = isDark ? '#1a1a1a' : '#ffffff';
})();
</script>
写作辅助脚本
最后让 Claude 帮我加了两个可以直接双击执行 .command 脚本:
| 脚本 | 用途 |
|---|---|
2_new_book_section.command | 交互式选书、选章、新建节,自动生成 frontmatter,自动算 weight = max + 1,建好同名图片目录 |
5_book_images.command | 把书节配套图片目录里的原图压缩成 webp、按 <section>_pNN.webp 重命名、上传到 S3 图床、打印 centered-image shortcode 复制粘贴 |
加上之前已有的 1_new_post.command(新建杂记)、3_hugo_server.command(本地预览)、4_post_images.command(杂记图片)、6_deploy.command(部署),我只要集中精力写作就可以了,剩下的都双击对应的脚本实现自动化。