Files
2026-05-18 17:29:18 +08:00

12 KiB
Raw Permalink Blame History

主题五大改进实施计划

任务一:Footer 配置组缺失

问题

Footer.astro 引用了 theme.config?.footer?.footer_copyrightfooter_icpfooter_socialsfooter_show_poweredfooter_show_themefooter_custom_html 等配置项,但 settings.yaml 中没有定义 footer 配置组,用户在后台无法设置页脚内容。

修改文件

  • settings.yaml — 新增 footer 配置组

具体改动

在 settings.yaml 的 comment 配置组之后新增 footer 配置组:

- group: footer
  label: 页脚
  formSchema:
    - $formkit: text
      name: footer_copyright
      label: 版权信息(留空则使用默认格式 © 年份 站点标题)
    - $formkit: text
      name: footer_icp
      label: ICP 备案号
    - $formkit: repeater
      name: footer_socials
      label: 社交链接
      children:
        - $formkit: text
          name: platform
          label: 平台名称
        - $formkit: text
          name: icon
          label: 图标类名(如 fa-brands fa-github
        - $formkit: url
          name: url
          label: 链接地址
    - $formkit: switch
      name: footer_show_powered
      label: 显示 "Powered by Halo"
      value: true
    - $formkit: switch
      name: footer_show_theme
      label: 显示主题版本
      value: true
    - $formkit: code
      name: footer_custom_html
      label: 自定义 HTML(统计代码等)
      language: html

任务二:SEO Meta 标签严重缺失

问题

Layout.astro<head> 中只有全站 description,缺少 og 标签、canonical URL、RSS 链接等。文章页应使用文章摘要作为 description。

修改文件

  • src/layouts/Layout.astro — 在 <head> 中添加 SEO meta 标签
  • src/pages/post.astro — 在 head slot 中添加文章页专属 SEO 标签
  • src/pages/page.astro — 在 head slot 中添加页面专属 SEO 标签

具体改动

Layout.astro — 全局 SEO 标签

在现有 <meta name="description"> 之后添加:

<meta name="keywords" th:content="${site.seo?.keywords}" />
<link rel="canonical" th:href="${site.url}" />
<link rel="alternate" type="application/rss+xml" th:title="${site.title}" th:href="@{/feed.xml}" />
<meta property="og:site_name" th:content="${site.title}" />
<meta property="og:type" content="website" />
<meta property="og:url" th:content="${site.url}" />
<meta property="og:title" th:content="${site.title}" />
<meta property="og:description" th:content="${site.seo?.description}" />
<meta name="twitter:card" content="summary" />

post.astro — 文章页专属 SEO 标签

<Fragment slot="head"> 中,<title> 之后添加:

<meta name="description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
<link rel="canonical" th:href="${post.status.permalink}" />
<meta property="og:type" content="article" />
<meta property="og:title" th:content="${post.spec.title}" />
<meta property="og:description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
<meta property="og:url" th:href="@{${post.status.permalink}}" />
<meta property="og:image" th:if="${post.spec.cover}" th:content="${post.spec.cover}" />
<meta property="article:published_time" th:content="${post.spec.publishTime}" />
<meta name="twitter:card" content="summary_large_image" th:if="${post.spec.cover}" />
<meta name="twitter:card" content="summary" th:unless="${post.spec.cover}" />
<meta name="twitter:title" th:content="${post.spec.title}" />
<meta name="twitter:description" th:content="${post.spec.excerpt ?: site.seo?.description}" />
<meta name="twitter:image" th:if="${post.spec.cover}" th:content="${post.spec.cover}" />

page.astro — 自定义页面专属 SEO 标签

<Fragment slot="head"> 中,<title> 之后添加:

<meta name="description" th:content="${singlePage.spec.excerpt ?: site.seo?.description}" />
<link rel="canonical" th:href="${singlePage.status.permalink}" />
<meta property="og:type" content="website" />
<meta property="og:title" th:content="${singlePage.spec.title}" />
<meta property="og:description" th:content="${singlePage.spec.excerpt ?: site.seo?.description}" />
<meta property="og:url" th:href="@{${singlePage.status.permalink}}" />

任务三:导航当前页面无高亮

问题

Navbar.astro 中 CSS 已定义 .wi-navbar__link--active 样式,但模板中没有为当前页面的导航链接添加 active 类名。

修改文件

  • src/components/Navbar.astro

具体改动

在导航链接 <a> 标签上添加 th:classappend 条件判断,通过比较当前请求路径与菜单项链接来判断是否高亮:

<a
  th:each="menuItem : ${menu.menuItems}"
  th:href="@{${menuItem.status.href}}"
  th:target="${menuItem.spec.target}"
  th:text="${menuItem.status.displayName}"
  class="wi-navbar__link"
  th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-navbar__link--active'"
>
</a>

同时需要在 MobileMenu.astro 中也添加同样的高亮逻辑。MobileMenu.astro 第 16-22 行的导航链接结构与 Navbar 相同:

<a
  th:each="menuItem : ${menu.menuItems}"
  th:href="@{${menuItem.status.href}}"
  th:target="${menuItem.spec.target}"
  th:text="${menuItem.status.displayName}"
  class="wi-mobile-menu__link"
  th:classappend="${#strings.equals(#request.requestURI, menuItem.status.href)} ? 'wi-mobile-menu__link--active'"
></a>

并在 MobileMenu.astro 的 <style> 中添加 active 样式:

.wi-mobile-menu__link--active {
  color: var(--accent);
  background: var(--bg-raised);
  font-weight: 600;
}

任务四:移动端文章目录不可用(浮动目录按钮)

问题

post.astro 中 TOC 仅在 min-width: 1280px 时显示,移动端没有任何替代方案。

修改文件

  • src/pages/post.astro

具体改动

1. 添加移动端浮动 TOC 按钮

在文章 <article> 内添加一个浮动按钮,仅在 max-width: 1279px 时显示:

<button
  th:if="${theme.config?.article?.article_show_toc ?: true}"
  class="wi-toc-fab"
  id="wi-toc-fab"
  type="button"
  aria-label="打开目录"
>
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" x2="21" y1="6" y2="6"/><line x1="8" x2="21" y1="12" y2="12"/><line x1="8" x2="21" y1="18" y2="18"/><line x1="3" x2="3.01" y1="6" y2="6"/><line x1="3" x2="3.01" y1="12" y2="12"/><line x1="3" x2="3.01" y1="18" y2="18"/></svg>
</button>

2. 添加移动端 TOC 抽屉面板

在浮动按钮之后添加一个从底部滑出的抽屉面板:

<div
  th:if="${theme.config?.article?.article_show_toc ?: true}"
  class="wi-toc-drawer"
  id="wi-toc-drawer"
>
  <div class="wi-toc-drawer__overlay"></div>
  <div class="wi-toc-drawer__panel">
    <div class="wi-toc-drawer__header">
      <span class="wi-toc-drawer__title">目录</span>
      <button class="wi-toc-drawer__close" type="button" aria-label="关闭目录">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
      </button>
    </div>
    <nav class="wi-toc-drawer__nav" id="wi-toc-drawer-nav"></nav>
  </div>
</div>

3. 添加 CSS 样式

.wi-toc-fab {
  display: none;
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--rule);
  background: var(--bg-raised);
  color: var(--ink-2);
  cursor: pointer;
  z-index: 20;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-md);
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.wi-toc-fab:hover {
  color: var(--accent);
  border-color: var(--accent);
}

@media (max-width: 1279px) {
  .wi-toc-fab {
    display: inline-flex;
  }
}

.wi-toc-drawer {
  display: none;
}

.wi-toc-drawer--open {
  display: block;
}

.wi-toc-drawer__overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 50;
}

.wi-toc-drawer__panel {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-height: 60vh;
  background: var(--bg);
  border-top: 1px solid var(--rule);
  border-radius: 16px 16px 0 0;
  padding: 1.25rem;
  z-index: 51;
  overflow-y: auto;
  transform: translateY(0);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.wi-toc-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--rule);
}

.wi-toc-drawer__title {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
}

.wi-toc-drawer__close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
}

.wi-toc-drawer__close:hover {
  color: var(--accent);
}

.wi-toc-drawer__nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.wi-toc-drawer__nav .wi-toc__link {
  font-size: var(--text-sm);
  padding: 6px 0;
}

4. 添加 JS 逻辑

在现有 <script is:inline> 中,TOC 构建逻辑之后,添加移动端抽屉逻辑:

var tocFab = document.getElementById("wi-toc-fab");
var tocDrawer = document.getElementById("wi-toc-drawer");
var tocDrawerNav = document.getElementById("wi-toc-drawer-nav");

if (tocFab && tocDrawer && tocDrawerNav && tocNav) {
  tocDrawerNav.innerHTML = tocNav.innerHTML;

  tocFab.addEventListener("click", function () {
    tocDrawer.classList.add("wi-toc-drawer--open");
    document.body.style.overflow = "hidden";
  });

  var drawerClose = tocDrawer.querySelector(".wi-toc-drawer__close");
  var drawerOverlay = tocDrawer.querySelector(".wi-toc-drawer__overlay");

  function closeDrawer() {
    tocDrawer.classList.remove("wi-toc-drawer--open");
    document.body.style.overflow = "";
  }

  if (drawerClose) drawerClose.addEventListener("click", closeDrawer);
  if (drawerOverlay) drawerOverlay.addEventListener("click", closeDrawer);

  tocDrawerNav.querySelectorAll(".wi-toc__link").forEach(function (link) {
    link.addEventListener("click", function () {
      closeDrawer();
    });
  });
}

任务五:404/500 页面深色模式不生效

问题

404.html500.html 是纯静态页面,没有读取 localStorage 中的主题偏好,首次直接访问错误页面时深色模式不会生效。

修改文件

  • public/error/404.html
  • public/error/500.html

具体改动

在两个文件的 <head> 中,<style> 标签之前,添加与 Layout.astro 相同的主题检测脚本(简化版,仅检测 localStorage 和系统偏好):

<script>
  (function () {
    var stored = localStorage.getItem("wi-theme");
    var prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
    var isDark = stored === "dark" || (!stored && prefersDark);
    if (isDark) {
      document.documentElement.classList.add("dark");
    }
  })();
</script>

这段脚本会在页面渲染前检测用户的主题偏好并添加 dark 类名,确保 CSS 变量正确切换。


执行顺序

  1. settings.yaml — 新增 footer 配置组
  2. Layout.astro — 添加全局 SEO meta 标签
  3. post.astro — 添加文章页 SEO 标签 + 移动端 TOC 浮动按钮和抽屉
  4. page.astro — 添加页面 SEO 标签
  5. Navbar.astro — 添加导航当前页面高亮
  6. MobileMenu.astro — 添加导航当前页面高亮(需先确认结构)
  7. 404.html — 添加深色模式检测脚本
  8. 500.html — 添加深色模式检测脚本
  9. 构建并部署到 Docker 验证