前言 #
作为一个程序员,拥有一个个人博客是展示技术成果、分享知识的重要方式。本文将详细介绍如何使用 Claude AI 辅助搭建一个功能丰富的 Hugo 博客,包括:
- 基于 Blowfish 主题的个性化配置
- Three.js 实现的魔方启动页效果
- 完整的中英文双语支持
- 导航收藏页功能
项目初始化 #
1. 创建 Hugo 项目 #
首先,我们需要创建一个 Hugo 项目并安装 Blowfish 主题:
# 创建新站点
hugo new site my-blog
# 进入项目目录
cd my-blog
# 初始化 git
git init
# 添加 Blowfish 主题
git submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfish2. 配置主题 #
Blowfish 主题采用模块化配置,配置文件位于 config/_default/ 目录下。主要配置文件包括:
| 文件 | 用途 |
|---|---|
params.toml |
主题参数配置 |
menus.en.toml |
英文菜单配置 |
menus.zh-cn.toml |
中文菜单配置 |
languages.en.toml |
英文语言配置 |
languages.zh-cn.toml |
中文语言配置 |
3. 使用 Claude 辅助开发 #
在项目初始化阶段,Claude 帮助完成了以下工作:
- 主题配置优化:调整配色、布局、功能开关等
- 多语言支持:配置中英文双语切换
- 自定义功能开发:魔方启动页、导航收藏页等
魔方启动页实现 #
这是本项目最具特色的功能 —— 用户需要解开魔方才能进入博客主页。
技术选型 #
- Three.js:用于 3D 渲染
- OrbitControls:实现魔方的拖拽旋转
- Tailwind CSS:UI 样式(Blowfish 主题内置)
核心实现思路 #
1. 魔方结构 #
魔方由 27 个小方块(Cubie)组成,每个方块有 6 个面,根据位置决定颜色:
// 魔方颜色 (标准配色)
const FACE_COLORS = {
R: 0xC41E3A, // 红 - 右面
L: 0xFF5800, // 橙 - 左面
U: 0xFFFFFF, // 白 - 上面
D: 0xFFD500, // 黄 - 下面
F: 0x009E60, // 绿 - 前面
B: 0x0051BA, // 蓝 - 后面
INNER: 0x1a1a1a // 内部颜色
};2. 旋转逻辑 #
魔方的旋转是核心难点,需要:
- 识别旋转层:根据操作(如 R、U、F)确定旋转轴和层
- 收集该层的方块:筛选出需要旋转的方块
- 执行旋转动画:使用四元数实现平滑旋转
- 更新状态:旋转完成后更新方块的位置和颜色状态
function rotateLayer(move, instant = false) {
return new Promise((resolve) => {
const info = getAxisAndLayer(move);
const { axis, layer, dir } = info;
const angle = (Math.PI / 2) * dir;
const layerCubies = getCubiesInLayer(axis, layer);
// 创建临时旋转组
const pivot = new THREE.Group();
scene.add(pivot);
layerCubies.forEach(c => pivot.add(c.mesh));
// 执行旋转动画...
});
}3. 打乱与还原 #
打乱魔方时,记录打乱序列,还原时执行逆操作:
// 打乱:生成随机序列
function generateScramble(length = 20) {
const MOVES = ['R', 'L', 'U', 'D', 'F', 'B', "R'", "L'", "U'", "D'", "F'", "B'"];
// 确保相邻操作不是同一面...
}
// 还原:执行打乱序列的逆操作
const solveSequence = [...scrambleSequence].reverse().map(m => getInverseMove(m));4. 手动模式状态跟踪 #
用户手动操作后,自动还原需要考虑手动操作的步骤:
// 记录手动操作
manualMoves.push(move);
// 自动还原时计算完整序列
if (manualMoves.length > 0) {
const undoManual = [...manualMoves].reverse().map(m => getInverseMove(m));
const originalSolve = [...scrambleSequence].reverse().map(m => getInverseMove(m));
solveSequence = [...undoManual, ...originalSolve];
}5. 粒子爆炸效果 #
魔方还原成功后,触发粒子爆炸动画:
function createParticleExplosion() {
const particles = [];
const colors = [FACE_COLORS.R, FACE_COLORS.L, ...];
for (let i = 0; i < PARTICLE_COUNT; i++) {
// 创建彩色粒子
const p = new THREE.Mesh(geo, mat);
p.userData.vel = new THREE.Vector3(
(Math.random() - 0.5) * 0.35,
(Math.random() - 0.5) * 0.35,
(Math.random() - 0.5) * 0.35
);
particles.push(p);
scene.add(p);
}
// 动画循环
function animateParticles() {
particles.forEach(p => {
p.position.add(p.userData.vel);
p.userData.vel.y -= 0.003; // 重力效果
p.scale.multiplyScalar(0.97); // 逐渐缩小
});
// ...
}
}文件结构 #
魔方功能相关的文件:
layouts/
├── index.html # 首页模板
└── partials/
└── home/
└── cube.html # 魔方组件
static/
└── js/
├── three.module.js # Three.js 核心库
└── OrbitControls.js # 轨道控制器中英文双语支持 #
Blowfish 主题原生支持多语言,我们进行了深度定制。
1. 菜单配置 #
英文菜单 (config/_default/menus.en.toml):
[[main]]
name = "Blog"
pageRef = "posts"
weight = 10
[[main]]
name = "Nav"
pageRef = "navlinks"
weight = 15
[[main]]
name = "About"
pageRef = "about"
weight = 40中文菜单 (config/_default/menus.zh-cn.toml):
[[main]]
name = "博客"
pageRef = "posts"
weight = 10
[[main]]
name = "导航"
pageRef = "navlinks"
weight = 15
[[main]]
name = "关于"
pageRef = "about"
weight = 402. 国际化文本 #
创建自定义翻译文件覆盖主题默认值:
i18n/zh-CN.yaml:
global:
language: "简体中文"
article:
reading_time:
one: "{{ .Count }} 分钟"
other: "{{ .Count }} 分钟"
table_of_contents: "目录"
footer:
powered_by: "由 {{ .Hugo }} & {{ .Theme }} & Claude 强力驱动"
navlinks:
no_links: "暂无导航链接,请在 data/navlinks.yaml 中添加"i18n/en.yaml:
global:
language: "English"
navlinks:
no_links: "No navigation links yet. Please add links in data/navlinks.yaml"3. 魔方界面国际化 #
在魔方组件中实现动态语言切换:
const i18n = {
'zh-cn': {
title: '解开魔方,进入博客',
autoSolve: '自动还原',
manualMode: '手动模式',
skip: '跳过',
// ...
},
'en': {
title: 'Solve the Cube to Enter',
autoSolve: 'Auto Solve',
manualMode: 'Manual Mode',
skip: 'Skip',
// ...
}
};
function getCurrentLang() {
const htmlLang = document.documentElement.lang || 'en';
if (htmlLang.startsWith('zh')) return 'zh-cn';
return 'en';
}
function updateI18nText() {
document.querySelectorAll('[data-i18n]').forEach(el => {
const key = el.getAttribute('data-i18n');
el.textContent = i18n[getCurrentLang()][key];
});
}HTML 中使用 data-i18n 属性标记需要翻译的元素:
<h1 data-i18n="title">解开魔方,进入博客</h1>
<button data-i18n="autoSolve">自动还原</button>导航收藏页功能 #
实现一个类似导航网站的页面,用于收藏常用链接。
1. 数据结构 #
创建 data/navlinks.yaml 存储链接数据:
categories:
- name: "开发工具"
icon: "code"
links:
- name: "GitHub"
url: "https://github.com"
icon: "github"
description: "全球最大的代码托管平台"
- name: "VS Code"
url: "https://code.visualstudio.com"
icon: "code"
description: "微软开源的代码编辑器"
- name: "AI 工具"
icon: "cpu"
links:
- name: "Claude"
url: "https://claude.ai"
icon: "bot"
description: "Anthropic 开发的 AI 助手"2. 页面模板 #
创建 layouts/navlinks/list.html:
{{ define "main" }}
<div class="container mx-auto px-4 py-8">
{{ range .Site.Data.navlinks.categories }}
<section class="mb-8">
<h2 class="text-2xl font-bold mb-4 text-neutral-800 dark:text-white">
{{ .name }}
</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{{ range .links }}
<a href="{{ .url }}" target="_blank" rel="noopener noreferrer"
class="block p-4 rounded-lg bg-neutral-100 dark:bg-neutral-800
hover:bg-neutral-200 dark:hover:bg-neutral-700
border border-neutral-200 dark:border-neutral-700
transition-all duration-200 hover:shadow-md">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-primary-100 dark:bg-primary-900
flex items-center justify-center">
<!-- 图标 -->
</div>
<div>
<h3 class="font-semibold text-neutral-800 dark:text-white">
{{ .name }}
</h3>
<p class="text-sm text-neutral-500 dark:text-neutral-400">
{{ .description }}
</p>
</div>
</div>
</a>
{{ end }}
</div>
</section>
{{ end }}
</div>
{{ end }}3. 深色模式适配 #
使用 Tailwind CSS 的 dark: 前缀实现深色模式:
<!-- 背景色 -->
class="bg-neutral-100 dark:bg-neutral-800"
<!-- 文字颜色 -->
class="text-neutral-800 dark:text-white"
<!-- 边框颜色 -->
class="border-neutral-200 dark:border-neutral-700"
<!-- 悬停状态 -->
class="hover:bg-neutral-200 dark:hover:bg-neutral-700"导航锁定功能 #
在魔方未解开时,禁用页面导航:
// 锁定导航
function lockPageNavigation() {
document.body.classList.add('cube-locked');
}
// 解锁导航
function unlockPageNavigation() {
document.body.classList.remove('cube-locked');
}CSS 样式:
body.cube-locked header,
body.cube-locked footer,
body.cube-locked nav,
body.cube-locked [class*="menu"],
body.cube-locked [class*="nav"] {
pointer-events: none !important;
}项目结构总览 #
my-blog/
├── config/
│ └── _default/
│ ├── params.toml # 主题参数
│ ├── menus.en.toml # 英文菜单
│ ├── menus.zh-cn.toml # 中文菜单
│ ├── languages.en.toml # 英文配置
│ └── languages.zh-cn.toml # 中文配置
├── content/
│ ├── posts/ # 博客文章
│ ├── navlinks/ # 导航页
│ └── about/ # 关于页
├── data/
│ └── navlinks.yaml # 导航链接数据
├── i18n/
│ ├── en.yaml # 英文翻译
│ └── zh-CN.yaml # 中文翻译
├── layouts/
│ ├── index.html # 首页模板
│ ├── navlinks/
│ │ └── list.html # 导航页模板
│ └── partials/
│ └── home/
│ └── cube.html # 魔方组件
├── static/
│ └── js/
│ ├── three.module.js
│ └── OrbitControls.js
└── themes/
└── blowfish/ # 主题目录总结 #
通过 Claude AI 的辅助,我们成功搭建了一个功能丰富的 Hugo 博客:
- 魔方启动页:使用 Three.js 实现 3D 魔方效果,支持自动还原和手动操作
- 双语支持:完整的中英文切换,包括菜单、界面文本、魔方提示
- 导航收藏页:卡片式布局,支持分类和深色模式
- 导航锁定:魔方未解开时禁用页面导航
经验总结 #
- 善用 AI 辅助:Claude 可以帮助快速实现复杂功能,但需要清晰的描述需求
- 模块化开发:将功能拆分为独立组件,便于维护和复用
- 状态管理:复杂交互需要仔细跟踪状态变化(如魔方的手动操作记录)
- 样式一致性:使用 Tailwind CSS 的
dark:前缀确保深色模式适配
参考资源 #
希望这篇文章对你有所帮助!如果你有任何问题,欢迎在评论区留言。