侧边栏云端文件树改造记录:中文目录、分类树与 SPA 导航

WordPress 迁移到 Hugo 后,顺手把主题(ark)的侧边栏云端文件树整体重构了一遍。这篇记录改造的思路、结构与踩坑,方便日后维护。

需求来源

原本的侧边栏云端树只有”按分类分组的文章 + 散落的页面链接”,分类和文件都是英文 slug,页面路径直接裸暴露(如 pages/friends/index.md),既不美观也不符合中文站点的使用习惯。改造目标是:

  1. 目录全部中文化,文件树里显示文章标题而不是英文 slug
  2. 结构分层:页面 / 归档 / 分类 / 标签 / 管理 五个一级目录
  3. 分类、标签做成文件树,可配置显示哪些分类
  4. 点击目录时:展开文件树 + 打开对应列表页,且不刷新浏览器(SPA)

最终结构

☁ 云端
├─ 📁 页面
│  ├─ Arkylin的小屋        ← 主页(显示网站名,点击回首页)
│  ├─ 示例页面.md(紫色)     ← pages 目录的页面,标题显示
│  └─ 友情链接.md ...
├─ 📁 归档                ← 链接到 /archives/
│  ├─ 📁 2019 (35)        ← 按年份分组,带文章计数
│  ├─ 📁 2020 (72)
│  └─ ...
├─ 📁 分类                ← 链接到 /categories/
│  ├─ 📁 学习(带链接)       ← 点击跳转 /categories/学习/
│  │  └─ 文章标题.md
│  └─ ...
├─ 📁 标签                ← 链接到 /tags/
│  ├─ Aliyun (1)
│  └─ ...(70 个,默认折叠)
└─ 📁 管理
   ├─ admin.md / settings.md / account.md

关键实现

1. 分类按配置显示

hugo.toml 里通过 [params.sidebar] 控制:

[params.sidebar]
  # 允许显示的分类文件夹(留空 = 全部显示)
  show_categories = ['学习', '开发', '日记', '代码', 'VPS测评', '记录', '测评', '未分类']

模板里用 in $showCats . 过滤分类文件夹;一篇文章有多个分类时,按分类分组(Go 模板 dict 累加),自然在多个分类文件夹里同时出现。

2. 点击目录:展开树 + SPA 打开页面

文件树的文件夹 label 用 <span data-tree-link="/categories/">,点击时由 JS 处理:

document.addEventListener('click', function (e) {
  var el = e.target.closest('[data-tree-link]');
  if (!el) return;
  var href = el.getAttribute('data-tree-link');
  if (!href) return;
  var d = el.closest('details');
  if (d) d.open = true;                 // 展开文件树
  if (typeof navigateTo === 'function') {
    navigateTo(href);                   // 主题自带 SPA 导航,不刷新
  } else {
    window.location.href = href;
  }
});

关键点:不要直接 window.location.href = href——主题(ark)有完整的 SPA 路由(navigateTo,fetch 页面 + DOMParser 替换内容),直接赋值会整页刷新,丢失编辑器 tab、树高亮等状态。点击后新页面树默认展开(<details open>)。

3. 层级引导线

云端树原本没有层级竖线,本地虚拟树有,视觉不一致。用伪元素 + 重复渐变实现连续列线(每行按深度画所有祖先列,避免”线被二级目录截断”):

.file-tree .tree-depth-1 > summary::after,
.file-tree .file-item.tree-depth-2::after,
/* ...depth 1-5 */
{
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: calc(13px + ((var(--tree-depth) - 1) * 12px) + 12px);
  background: repeating-linear-gradient(
    to right,
    transparent 0 12px,
    color-mix(in srgb, var(--line) 68%, transparent) 12px 13px
  );
}

4. 目录行高统一(踩坑)

文件夹的 summary 是 3 列网格 grid-template-columns: 16px 18px minmax(0, 1fr)。给”年份文件夹”加文章计数后变成 4 个元素,第 4 个被挤到下一行,行高直接翻倍(22px → 44px),看起来”有的目录大有的小”:

.file-tree .tree-folder.is-year > summary {
  grid-template-columns: 16px 18px minmax(0, 1fr) auto;
}

另外,文件夹 label 用 <a><span> 渲染观感不同(链接有默认交互样式),统一用 <span> + JS 跳转,目录大小/颜色才完全一致。分类文件夹原有的蓝色图标也一并改回灰色,与标签/归档文件夹统一。

遗留

  • 本地虚拟树(浏览器本地文件)和云端树结构不同,云端已中文化,本地保持原样
  • extra_dirs 配置项已废弃(归档固定为一级目录),如需在页面文件夹下追加自定义目录可恢复该逻辑

相关文件

  • themes/ark/layouts/partials/sidebar.html — 云端树模板 + 点击跳转 JS
  • themes/ark/assets/css/ark-sidebar.7d3ea819.css — 引导线、is-year 网格、label 样式
  • hugo.toml[params.sidebar] 分类显示配置