# Somnia 主题架构概述


> 提醒：本文档为 AI 生成，如需使用请自行验证其内容。

Somnia 是一个基于 Hugo 的主题，适用于内容型网站（博客、文档、个人主页）。
在保持 SEO 友好的同时借助 Swup.js 提供接近 SPA 的流畅体验。

> 技术栈：Hugo + Alpine.js + UnoCSS + Swup.js + Medium Zoom

<!--more-->

## 设计定位

适合**内容型网站或轻量级 Web 应用**，在以下两个目标之间取得平衡：

- **SEO 友好** — Hugo 服务端渲染输出完整 HTML，搜索引擎可直接索引
- **SPA 体验** — Swup.js 拦截页面间导航，AJAX 加载内容，无刷新过渡

## 目录

- [技术架构总览](#技术架构总览)
- [主题自定义机制](#主题自定义机制)
- [Hugo 模板体系](#hugo-模板体系)
- [JavaScript 架构](#javascript-架构)
- [CSS 样式体系](#css-样式体系)
- [短代码组件](#短代码组件)
- [配置参数](#配置参数)
- [补充说明](#补充说明)

---

## 技术架构总览

```
用户请求 ─→ Hugo（SSG）─→ 静态 HTML ─→ 浏览器
                                │
                    Swup.js 拦截同站导航 ←→ AJAX 加载新页面
                        │
                Alpine.js 重新初始化组件
                        │
                Async Alpine 按需加载第三方库
```

| 层次 | 技术 | 定位 |
|------|------|------|
| 生成 | Hugo v0.158.0+ | 扩展版，服务端渲染 |
| 样式 | UnoCSS 66.x | 原子化 CSS，4 个预设 |
| 交互 | Alpine.js 3.14+ | 声明式 DOM 绑定，15 个指令 |
| 懒加载 | Async Alpine | 代码分割，按需加载组件 |
| 导航 | Swup.js | 无刷新页面过渡 |
| 滚动 | Swup Scroll Plugin | 切换时保存/恢复滚动位置 |
| 预加载 | Swup Preload Plugin | 悬停链接时预加载资源 |
| 图片缩放 | Medium Zoom | 点击放大预览 |

---

## 主题自定义机制

Hugo 查找优先级：**website > theme**

```
website/assets/js/custom.js     ← 优先使用
website/themes/Somnia/assets/js/custom.js  ← 仅当前者不存在时
```

**核心原则：** 在 `website/` 下创建与主题同路径的文件即可覆盖，无需修改主题源码。
覆盖的文件不会随主题更新而变化，升级时需手动 diff 合并。

--- 

## Hugo 模板体系

### 布局文件结构

```
layouts/
├── _default/                 # 默认布局
│   ├── baseof.html           # 全局骨架（html/head/body 结构）
│   ├── home.html             # 首页
│   ├── single.html           # 单页面
│   └── list.html             # 列表页
├── posts/                    # 博客文章
├── docs/                     # 文档页面
├── categories/               # 分类聚合
├── tags/                     # 标签聚合
├── partials/                 # 可复用组件
│   ├── head/                 # head 子组件（theme.html、css.html、js.html）
│   ├── header.html           # 导航栏
│   ├── footer.html           # 页脚
│   ├── home/                 # 首页区块
│   ├── page/                 # 页面级组件（hero、article-info、copyright 等）
│   ├── toc/                  # 目录组件（嵌套 TOC 生成流水线）
│   ├── comment/              # 评论系统（Artalk / Mastodon）
│   └── back-to-top.html      # 回到顶部（含阅读进度）
└── shortcodes/               # 22 个短代码
```

### 关键模板说明

- **baseof.html** — 定义 `--highlightColor` CSS 变量，`#content-wrapper` 为 Swup 切换容器
- **head/theme.html** — 内联脚本，DOM 渲染前从 localStorage 读取主题，防闪烁
- **data.html** — 通过 `data-somnia` 属性触发 KaTeX 等第三方库按需加载

---

## JavaScript 架构

### 文件组织

```
assets/js/
├── variable.js               # 全局变量（CDN 路径等）
├── main.js                   # Somnia 核心类（工具方法 + 第三方库管理）
├── components.js              # Alpine.js 组件函数（10 个组件）
├── custom.js                 # 用户自定义，可覆盖欢迎语、CDN 路径、初始化钩子
├── alpinejs.min.js           # Alpine.js 框架（v3.14+）
├── async-alpine.min.js       # 异步加载 Alpine 组件适配器
├── medium-zoom.min.js        # 图片缩放库
├── sw.js                     # PWA Service Worker（可选）
└── swup/                     # Swup 无刷新导航库
    ├── Swup.umd.js           # 核心
    ├── preload-plugin.js     # 悬停预加载
    └── scroll-plugin.js      # 滚动位置管理
```

### 加载顺序

1. `head/theme.html` 内联脚本初始化主题色（防闪烁）
2. `head/js.html` 按顺序加载：
   - **variable.js** → 定义全局变量（如 `SOMNIA_LIBS`、`BASE_URL`）
   - **main.js** → 实例化 `Somnia` 类，定义工具方法和第三方库管理器
   - **components.js** → 通过 `alpine:init` 注册 Alpine 组件和全局 Store
   - **custom.js** → 用户覆盖的 welcome 信息、CDN 路径、初始化钩子
   - **Swup.js + 插件** → 初始化无刷新导航，绑定 `#content-wrapper`
   - **Alpine.js** → 扫描 DOM 中的 `x-data` 指令，初始化组件

### 模块职责

| 文件 | 职责 |
|------|------|
| `variable.js` | 存储全局变量、配置参数，在各模块间共享 |
| `main.js` | 主入口，初始化全局 `Somnia` 实例，提供 `showToast`、`loadResource`、`timestampToShichen`、`scanLine` 等工具方法 |
| `components.js` | `Alpine.store('somnia')`（主题/暗色状态）、10 个组件函数：`headerComponent`、`mainComponent`、`backToTopComponent`、`quoteComponent`、`heroComponent`、`tocComponent`、`somniaData`、`searchComponent` 等 |
| `custom.js` | 用户自定义逻辑，可覆盖 `PageInitCustom()` 和 `swupPageInitCustom()` 钩子 |

### 第三方库管理

`Somnia.prototype.libs` 实现了一套通用的库加载/运行接口，每个库有 `loaded()`、`ok()`、`load()`、`run()` 四个方法：

| 库 | 加载方式 | 触发条件 |
|----|---------|---------|
| Medium Zoom | 全局打包 | 始终可用，Swup 切换后自动重新绑定 |
| Pagefind | 按需 CSS + JS | 搜索页面 `searchComponent()` 加载 |
| KaTeX | 按需 CSS + JS | 文章 Front Matter 设 `math: true` |

### Swup.js 与 Alpine.js 的协作

- Swup 拦截链接点击 → AJAX 获取新页面 → 替换 `#content-wrapper` → 触发页面切换事件
- Alpine.js 自动检测新 DOM 中的 `x-data` 指令并初始化
- **组件开发关键：** Swup 切换后 `<script>` 标签不会自动执行，因此 shortcode 中的 `x-data="fn()"` 需要额外处理。详见[组件编写指南](components)。

---

## CSS 样式体系

### 文件组织

```
assets/css/
├── uno.css               # UnoCSS 自动生成（运行 pnpm build 后生成）
├── main.css              # 核心样式
│   ├── fade-in-up 动画   # 内容元素按序淡入（50ms/100ms/150ms 延迟链）
│   ├── KaTeX 公式样式     # 公式容器滚动、对齐
│   └── Shiki 代码块样式   # 圆角、行号、语言标签、复制按钮
├── components.css        # 组件独有样式
│   ├── 导航栏滚动效果     # 粘性定位、阴影、移动端菜单动画
│   └── 主题切换按钮       # dark/light/system 图标切换
├── app.css               # 应用级全局样式
├── custom.css            # 用户自定义覆盖
├── medium-zoom.css       # 图片缩放样式
├── tailwind.css          # Tailwind 兼容层
└── code/                 # 代码高亮主题
```

### UnoCSS 体系

Somnia 使用 UnoCSS 作为原子化 CSS 引擎，通过 `uno.config.ts` 配置：

- **presetMini** — 基础预设（必需）
- **presetAttributify** — 属性化模式：`<div p-4>` 替代传统 class
- **presetTypography** — 排版预设：自定义 `prose` 类，覆盖标题锚点、引用块、表格、列表、内联代码等
- **themeColors** — CSS 变量映射到工具类：`text-primary`、`bg-muted`、`border-border`

开发时需同时运行 UnoCSS 监听进程：

```bash
pnpm unocss "layouts/**/*.html" -o ./assets/css/uno.css --watch
```

### CSS 变量主题色

所有颜色通过 CSS 变量在 `:root` 和 `.dark` 中定义，通过 UnoCSS 的 `themeColors` 映射到工具类：

| 变量 | 用途 | 对应类 |
|------|------|--------|
| `--primary` | 主色调（高亮色） | `text-primary`、`bg-primary` |
| `--foreground` / `--background` | 文字/背景 | `text-foreground`、`bg-background` |
| `--muted` / `--muted-foreground` | 柔和色 | `bg-muted`、`text-muted-foreground` |
| `--border` / `--input` / `--ring` | 边框/输入框/焦点环 | `border-border` 等 |
| `--radius` | 圆角 | `rounded-*` |
| `--highlightColor` | 渐变高亮色 | 内联 `style` |

### 加载方式

通过 `head/css.html` 用 Hugo Pipes 加载：

```html
{{ $css := resources.Get "css/main.css" | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}">
```

> **注意：** CSS `@import` 语法需要 Hugo >= v0.158.0 支持。

---

## 短代码组件

Somnia 内置了 22 个短代码，分为四类：

| 类别 | 短代码 | 说明 |
|------|--------|------|
| 基础 | `card`、`callout`、`label`、`quote`、`toast` | 卡片、提示框（4 种风格）、标签、引用、消息 |
| 布局 | `tabs`、`collapse`、`timeline`、`steps` | 标签页、折叠面板、时间线、步骤指示器 |
| 增强 | `qrcode`、`link-preview`、`github-card`、`bilibili`、`formatted-date` | 二维码、链接预览、GitHub 卡片、B站嵌入、日期 |
| 工具 | `card-list`、`md2html`、`script`、`date` | 列表容器、Markdown 转 HTML、脚本嵌入 |

> 完整用法和参数说明见[组件文档](components)。

---

## 配置参数

站点 `hugo.toml` 的 `[params]` 下可配置：

| 参数路径 | 说明 |
|---------|------|
| `params.limit` | 分页：blogPosts/blogCategories/blogTags 等 |
| `params.author` | 名称、邮箱、头像、GitHub、简介 |
| `params.homepage` | 首页文章数、一言开关 |
| `params.header.menu` | 导航栏菜单项列表 |
| `params.footer` | 页脚：ICP 备案、版权信息 |
| `params.features` | 功能开关（search 等） |
| `params.comment` | 评论系统（provider: Artalk / Mastodon） |
| `params.education` / `params.certifications` | 首页教育/证书区块 |
| `params.websites` | 首页友情网站列表 |
| `params.skills` | 首页技能标签 |

> 完整配置示例见 `exampleSite/config/_default/hugo.toml`。

---

## 补充说明

### 版本要求

- Hugo extended，最低 v0.158.0（CSS `@import` 支持）
- pnpm v10+（UnoCSS 构建）
- Node.js 20+（推荐）
- Pagefind（可选，搜索索引）

### 相关文档

- [组件编写指南](components) — Swup.js 环境下 Alpine.js 组件的 5 种写法
- [开发指南](https://github.com/kkbt0/Somnia/blob/main/docs/development-guide.md) — 完整项目文档
