
博客迁移
0x00 前言
之前的博客使用的是Hexo框架,但是用久了感觉有点low,配不上我了,就给换了。刚好逛github看见一个美丽的主题(这个我肯定不换了,我会爱一辈子的),可惜是用的Astro,所以还麻烦我学习了一番,现在也是部署成功了喵喵喵
0x01 本地运行
打开fuwari项目,按照文档fork项目,然后clone到本地,然后执行命令即可
下列指令均需要在项目根目录执行:
Command | Action |
---|---|
pnpm install 并 pnpm add sharp | 安装依赖 |
pnpm dev | 在 localhost:4321 启动本地开发服务器 |
pnpm build | 构建网站至 ./dist/ |
pnpm preview | 本地预览已构建的网站 |
pnpm new-post <filename> | 创建新文章 |
pnpm astro ... | 执行 astro add , astro check 等指令 |
pnpm astro --help | 显示 Astro CLI 帮助 |
本地调试只要用到前两个,pnpm dev
之后就能在本地看到网页了
0x03 魔改主题
之前一直不换,主要因为原本的博客有个live2d模型,hexo搞这个很方便,但是Astro我完全不熟,但是都决定转过来了,那还是老老实实学着搞一下吧,结果搜半天也没搜到相关的,这扯不扯,还得自己搞
直接使用live2d这个库,简直好用到爆炸,我的模型也用的这个仓库里的(我用过的你们就不准用了,看在我教你们搞的份上qwq)
首先去展示页面挑个自己喜欢的模型,然后记好路径,下载仓库,进去找到对应模型文件夹
然后进入fuwari的目录,找到/src/layouts/Layout.astro
,我们主要修改这个文件
一、添加live2d模型
1. 添加 Live2D 脚本引用
定位方法:在 Layout.astro
中搜索 </head>
找到后,在 </head>
标签之前添加:
<!-- Live2D --><script src="/live2d/live2d.js"></script>
2. 添加 Live2D 容器
定位方法:在 Layout.astro
中搜索 <div id="page-height-extend"
找到这行:
<!-- increase the page height during page transition to prevent the scrolling animation from jumping --><div id="page-height-extend" class="hidden h-[300vh]"></div>
在这行之前添加:
<!-- Live2D Widget --><div id="live2d-widget" class="fixed bottom-0 left-0 z-50 hidden md:block"> <canvas id="live2d" width="280" height="350"></canvas></div>
3. 添加 Live2D 初始化函数
定位方法:在 Layout.astro
中搜索 function init() {
你会看到类似这样的代码:
function init() { // disableAnimation()() // TODO loadTheme(); loadHue(); initCustomScrollbar(); showBanner();}
修改步骤:
- 在
function init() {
之前添加新函数:
function initLive2D() { if (typeof loadlive2d !== 'undefined') { try { loadlive2d("live2d", "/live2d/model/model.json"); } catch (error) { console.error("Failed to load Live2D model:", error); } }}
- 在
init()
函数内部,showBanner();
这行之后添加:
initLive2D();
4. (可选)添加自定义样式
定位方法:搜索 <style is:global
在这个样式块的 }
结束标记之前添加:
/* Live2D styles */#live2d-widget { pointer-events: none; opacity: 0.9;}#live2d { pointer-events: auto;}
然后然后,把模型和js文件放到/public/live2d/
下(这个文件夹自己创建),结构如下:
live2d.│ LAppDefine.js│ live2d.js│└─model │ model.json │ model.moc │ physics.json │ ├─model.1024 │ texture_00.png │ └─motions broken_1.mtn broken_2.mtn broken_3.mtn broken_4.mtn broken_5.mtn daiji.mtn login.mtn shake.mtn wait_1.mtn
每个人模型里的文件不一样,结构和我一样就行了,然后执行pnpm dev
打开网页应该就有效果了qwq
配置完可以稍微设置一下
/* Live2D styles */#live2d-widget { pointer-events: none; opacity: 0.8; /* 透明度:0-1之间,0.8 = 80%透明度 */ position: fixed; left: 10px; /* 距离左边的距离 */ bottom: 10px; /* 距离底部的距离 */ transform: scale(0.8); /* 缩放:0.8 = 80%大小 */ transform-origin: bottom left; /* 缩放中心点设在左下角 */}#live2d { pointer-events: auto;}
二、添加文章置顶功能
1.更新配置文件
frontmatter.json
:添加 pinned 字段的配置
"title": "language", "name": "language", "type": "string"+ },+ {+ "title": "pinned",+ "name": "pinned",+ "type": "boolean" } ] }
src/content/config.ts
:在文章 schema 中添加pinned
tags: z.array(z.string()).optional().default([]), category: z.string().optional().default(""), lang: z.string().optional().default(""),+ pinned: z.boolean().optional().default(false),
/* For internal use */ prevTitle: z.string().default(""),
2.更新新建文章脚本
scripts/new-post.js
:在模板中添加pinned: false
默认值
tags: [] category: ''-draft: false+draft: false lang: ''+pinned: false ---
3.更新文章排序逻辑
src/utils/content-utils.ts
:修改排序函数,置顶文章优先显示
const sorted = allBlogPosts.sort((a, b) => {+ // First sort by pinned status (pinned posts come first)+ if (a.data.pinned && !b.data.pinned) return -1;+ if (!a.data.pinned && b.data.pinned) return 1;++ // Then sort by date (newest first) for posts with the same pinned status const dateA = new Date(a.data.published); const dateB = new Date(b.data.published); return dateA > dateB ? -1 : 1;
4.更新 PostCard 组件
src/components/PostCard.astro
:添加 pinned 属性和图钉图标
在 interface 中添加:
draft: boolean; style: string;+ pinned?: boolean; }
在解构中添加:
description, style,+ pinned, } = Astro.props;
在标题处添加图钉图标:
before:absolute before:top-[35px] before:left-[18px] before:hidden md:before:block ">+ {entry.data.pinned &&+ <Icon class="inline-block text-[1.2rem] text-[var(--primary)] mr-1 align-middle translate-y-[-2px]" name="material-symbols:push-pin" />+ } {title} <Icon class="inline text-[2rem] text-[var(--primary)] md:hidden translate-y-0.5 absolute" name="material-symbols:chevron-right-rounded" ></Icon>
5.更新 ArchivePanel 组件
src/components/ArchivePanel.astro
:导入 Icon 组件并添加图钉显示
添加导入:
import { getPostUrlBySlug } from "../utils/url-utils";+import { Icon } from "astro-icon/components";
在文章标题处添加:
text-75 pr-8 whitespace-nowrap overflow-ellipsis overflow-hidden" >+ {post.data.pinned &&+ <Icon class="inline-block text-[1rem] text-[var(--primary)] mr-1 align-middle translate-y-[-1px]" name="material-symbols:push-pin" />+ } {post.data.title} </div>
6.更新 PostPage 组件
src/components/PostPage.astro
:传递 pinned 属性
draft={entry.data.draft}+ pinned={entry.data.pinned} class:list="onload-animation"
使用方法: 在文章的 frontmatter 中设置 pinned: true
即可将文章置顶。
三、添加评论系统
这里直接用Twikoo,创建账号后端部署什么的自己去看官方文档,我这里直接改前端代码了
1.创建Twikoo组件
首先在/src/components/misc/
创建Twikoo.astro作为评论组件
---interface Props { path: string;}
const config = { el: "#comment", path: Astro.props.path,};---
<div id="comment"></div><script define:vars={{ config }}>let twikooInitialized = false;
function loadTwikoo() { if (twikooInitialized) return;
const commentContainer = document.getElementById('comment'); if (!commentContainer) return;
const script = document.createElement("script"); script.src = "https://cdn.jsdelivr.net/npm/twikoo@1.6.41/dist/twikoo.all.min.js"; script.defer = true; script.onload = () => { twikoo.init({ ...config, envId: "https://yuukiii.netlify.app/.netlify/functions/twikoo", lang: "zh-CN", }); twikooInitialized = true; }; document.body.appendChild(script);}
window.loadTwikoo = loadTwikoo;document.addEventListener("loadComment", loadTwikoo);
if (document.readyState === 'complete') { setTimeout(loadTwikoo, 100);} else { window.addEventListener('load', () => { setTimeout(loadTwikoo, 100); });}</script>
2.在Layout中注册
进到/src/layouts/layout.astro
新增如下函数
function initCommentComponent() { // 方法1: 分发事件(保留原有方式) const event = new Event("loadComment"); document.dispatchEvent(event);
// 方法2: 直接调用函数(新增的方式) if (typeof window.loadTwikoo === 'function') { window.loadTwikoo(); } else { // 如果函数还没准备好,稍后重试 setTimeout(() => { if (typeof window.loadTwikoo === 'function') { window.loadTwikoo(); } }, 200); }}
// 添加到全局作用域window.initCommentComponent = initCommentComponent;
在init
中调用
// 延迟调用评论组件初始化,并且多次尝试 const tryInitComment = () => { const commentContainer = document.getElementById('comment'); if (commentContainer) { window.initCommentComponent(); } else { // 如果评论容器还不存在,稍后重试 setTimeout(tryInitComment, 100); } };
setTimeout(tryInitComment, 100);
window.swup.hooks.on( "content:replace", () => { lightbox?.destroy?.()+ window.initCommentComponent(); }, { before: true }, )
3.(可选)添加自定义样式
默认样式在网站里显得十分不和谐,这里自定义一下样式
在/src/style/
下随便创建个css,然后自己改改样式,这里是我的,抄的网上别人的
:root { --tk-text: black;}
html.dark { --tk-text: #d1d5db;}
.tk-comments { @apply text-[var(--tk-text)];}
.tk-submit { .tk-avatar { @apply hidden; }}
/* Text Area */.tk-row { .tk-col { @apply flex-col-reverse; .tk-input { textarea { @apply rounded-[var(--radius-large)] py-4 px-6 !min-h-[150px] focus:border-[var(--primary)]; } } }}
.el-input { @apply !rounded-lg;}
.tk-meta-input { @apply min-h-10 relative mt-3; .el-input-group__prepend { @apply !bg-inherit; } div { @apply py-1 rounded-l-lg; min-height: inherit; } input { @apply px-4 rounded-r-lg focus:!border-[var(--primary)]; min-height: inherit; }}
/* Button */.tk-row.actions { @apply w-full !ml-0 !mt-0; .__markdown { @apply !hidden; } .tk-preview, .tk-send, .tk-cancel { @apply border-none rounded-lg px-3 py-0 h-8 !bg-[var(--btn-regular-bg-active)] disabled:!bg-[var(--btn-regular-bg)] !text-[var(--btn-content)] disabled:!text-[#ffffffa1]; }}
/* Comment title */.tk-comments-title { .__comments svg { @apply fill-[var(--primary)]; }}
.tk-comment { @apply border-[1px] border-[rgba(144,147,153,0.31)] p-4 rounded-2xl hover:shadow-md transition-all; .tk-action-icon svg { @apply fill-[var(--primary)]; }}
.tk-action { .tk-action-count { @apply text-[var(--btn-content)]; }}
.tk-meta { .tk-tag { @apply border-none rounded-lg text-[var(--btn-content)]; }
.tk-tag-green { @apply bg-[var(--btn-regular-bg)] dark:bg-[var(--primary)] dark:text-[var(--deep-text)]; }}
.tk-content,.tk-preview-container { a { /* 使用纯 CSS 避免 Tailwind 语法限制 */ text-decoration: underline; color: var(--primary); font-weight: 500; transition: color 0.2s ease; }
a:hover { color: var(--primary); opacity: 0.8; }
.tk-ruser { @apply no-underline; }
:not(pre) > code { @apply bg-[var(--inline-code-bg)] rounded-md px-1 py-0.5 font-semibold; color: var(--inline-code-color); }
li{ @apply before:content-['•'] before:text-[var(--primary)]; }}
/* Replies */.tk-replies { .tk-comment { @apply bg-[var(--page-bg)]; .tk-content { > span:first-of-type { @apply text-xs; } } }}
.twikoo .code-block { pre { @apply !rounded-xl; }
.copy-btn-icon { width: inherit !important; height: inherit !important; }}
.tk-expand-wrap .tk-expand,.tk-collapse-wrap .tk-expand { @apply hover:rounded-lg mt-1 hover:bg-[var(--btn-plain-bg-hover)];}
0x03 部署网站
之前使用HEXO的时候是挂在Github Page上的,但是国内访问Github似乎不是很友好,所以这次选择部署到Netlify。由于刚刚是在本地修改的代码,现在需要先把他push到github
cd 你的项目目录git statusgit add .git commit -m "修改了XXX功能"git push origin main
然后去Netlify导入Github的对应项目,然后一路默认选项即可,后面你push代码之后,Netlify会自动帮你构建发布,太尼玛人性化了,等我工作有米了我必须狠狠支持你一下。
然后就是自定义域名的问题,项目部署完成之后,可以点击第2步Set up a custom domain
,然后进去自己随便配置一下就ojbk了,这个应该都会的,然后就搞定了
0x04 小结
又浪费了我两天时间,但是我有强迫症,这个事情做不完我会很难受。好在结果还行ξ( ✿>◡❛)