2149 words
11 minutes
New Blog!!!
2025-07-15

博客迁移#

0x00 前言#

之前的博客使用的是Hexo框架,但是用久了感觉有点low,配不上我了,就给换了。刚好逛github看见一个美丽的主题(这个我肯定不换了,我会爱一辈子的),可惜是用的Astro,所以还麻烦我学习了一番,现在也是部署成功了喵喵喵

0x01 本地运行#

打开fuwari项目,按照文档fork项目,然后clone到本地,然后执行命令即可

下列指令均需要在项目根目录执行:

CommandAction
pnpm installpnpm add sharp安装依赖
pnpm devlocalhost: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();
}

修改步骤:

  1. 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);
}
}
}
  1. init() 函数内部,showBanner(); 这行之后添加:
initLive2D();

4. (可选)添加自定义样式#

定位方法:搜索 <style is:global

在这个样式块的 } 结束标记之前添加:

/* Live2D styles */
#live2d-widget {
pointer-events: none;
opacity: 0.9;
}
#live2d {
pointer-events: auto;
}

然后然后,把模型和js文件放到/public/live2d/下(这个文件夹自己创建),结构如下:

Terminal window
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

Terminal window
cd 你的项目目录
git status
git add .
git commit -m "修改了XXX功能"
git push origin main

然后去Netlify导入Github的对应项目,然后一路默认选项即可,后面你push代码之后,Netlify会自动帮你构建发布,太尼玛人性化了,等我工作有米了我必须狠狠支持你一下。

然后就是自定义域名的问题,项目部署完成之后,可以点击第2步Set up a custom domain,然后进去自己随便配置一下就ojbk了,这个应该都会的,然后就搞定了

0x04 小结#

又浪费了我两天时间,但是我有强迫症,这个事情做不完我会很难受。好在结果还行ξ( ✿>◡❛)

New Blog!!!
https://yuuki.cool/posts/newblog/newblog/
Author
Yuuki
Published at
2025-07-15
License
CC BY-NC-SA 4.0