Enable content separation

This commit is contained in:
2025-12-08 14:41:07 +08:00
parent 45906e6e0f
commit c1a601fbde
45 changed files with 1075 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
{
"mode": "external",
"hidden": true,
"title": "外链相册示例",
"description": "这是一个使用外链图片的相册示例,所有图片都来自外部链接",
"date": "2025-08-28",
"location": "网络",
"tags": ["外链", "示例", "测试"],
"layout": "masonry",
"columns": 3,
"cover": "https://picsum.photos/800/600?random=1",
"photos": [
{
"id": "external-1",
"src": "https://picsum.photos/800/600?random=2",
"alt": "随机图片 1",
"title": "美丽的风景",
"description": "这是一张来自外链的美丽风景图片",
"tags": ["风景", "自然"],
"width": 800,
"height": 600
}
]
}

View File

@@ -0,0 +1,211 @@
# 相册功能使用说明
Mizuki 主题的相册功能采用**自动扫描**机制,只需创建文件夹、放置图片和配置文件即可,无需手动编写代码(外链相册则需要手动定义每张图片的 `src` 等信息)。
## 快速开始
创建一个相册只需 3 步:
1.`public/images/albums/` (本说明文件所在目录)下创建一个文件夹(文件夹名即为相册 ID
2. 在文件夹中放置 `cover.jpg`(封面图)和其他照片
3. 创建 `info.json` 配置文件
完成!相册会自动出现在相册列表页面。
## 目录结构
```
public/images/albums/
├── my-travel-2024/ # 相册文件夹(文件夹名 = 相册ID
│ ├── info.json # 相册配置文件(必需)
│ ├── cover.jpg # 封面图(必需)
│ ├── photo1.jpg # 相册照片
│ ├── photo2.jpg
│ └── photo3.jpg
├── daily-life/ # 另一个相册
│ ├── info.json
│ ├── cover.jpg
│ └── ...
└── README.md # 本说明文件
```
## 配置文件说明
### 本地图片模式
在相册文件夹中创建 `info.json`
```json
{
"title": "我的旅行相册",
"description": "2024年夏天的美好回忆",
"date": "2024-08-01",
"location": "日本东京",
"tags": ["旅行", "风景", "夏天"],
"layout": "masonry",
"columns": 3,
"hidden": false
}
```
**配置项说明:**
| 字段 | 必需 | 说明 | 默认值 |
|------|------|------|--------|
| `title` | 是 | 相册标题 | 使用文件夹名 |
| `description` | 否 | 相册描述 | 空 |
| `date` | 否 | 相册日期格式YYYY-MM-DD | 当前日期 |
| `location` | 否 | 拍摄地点 | 空 |
| `tags` | 否 | 标签数组 | `[]` |
| `layout` | 否 | 布局方式:`grid`(网格)或 `masonry`(瀑布流) | `grid` |
| `columns` | 否 | 列数2-4 | `3` |
| `hidden` | 否 | 是否隐藏相册 | `false` |
### 外链图片模式
如果想使用外部图片链接(例如使用图床),设置 `mode: "external"`
```json
{
"mode": "external",
"title": "外链相册示例",
"description": "使用外部图片链接的相册",
"date": "2024-08-28",
"location": "网络",
"tags": ["外链", "示例"],
"layout": "masonry",
"columns": 3,
"cover": "https://example.com/cover.jpg",
"photos": [
{
"id": "photo-1",
"src": "https://example.com/photo1.jpg",
"alt": "图片描述",
"title": "图片标题",
"description": "详细描述",
"tags": ["标签1"],
"width": 1920,
"height": 1280
}
]
}
```
**外链模式额外字段:**
| 字段 | 必需 | 说明 |
|------|------|------|
| `mode` | 是 | 设置为 `"external"` 启用外链模式 |
| `cover` | 是 | 封面图片 URL (仅外链模式需要) |
| `photos` | 是 | 照片数组,每张照片包含 `src``alt``title` 等字段,详见下表 |
**photos 数组中每张图片的字段说明(仅外链模式需要):**
| 字段 | 必需 | 说明 | 示例 |
|------|------|------|------|
| `id` | 否 | 照片唯一标识符 | `"photo-1"` |
| `src` | 是 | 照片 URL 地址 | `"https://example.com/photo.jpg"` |
| `thumbnail` | 否 | 缩略图 URL不提供则使用原图 | `"https://example.com/thumb.jpg"` |
| `alt` | 否 | 图片替代文本(用于无障碍访问) | `"美丽的日落"` |
| `title` | 否 | 照片标题 | `"海边日落"` |
| `description` | 否 | 照片详细描述 | `"2024年夏天在海边拍摄的日落"` |
| `tags` | 否 | 照片标签数组 | `["日落", "海边"]` |
| `date` | 否 | 拍摄日期格式YYYY-MM-DD | `"2024-08-01"` |
| `location` | 否 | 拍摄地点 | `"冲绳海滩"` |
| `width` | 否 | 照片宽度(像素) | `1920` |
| `height` | 否 | 照片高度(像素) | `1280` |
| `camera` | 否 | 相机型号 | `"Canon EOS R5"` |
| `lens` | 否 | 镜头型号 | `"RF 24-70mm F2.8"` |
| `settings` | 否 | 拍摄参数(字符串) | `"f/2.8, 1/500s, ISO 100"` |
> **注意**
> - 本地图片模式**不需要**配置 `photos` 字段,系统会自动扫描文件夹中的所有图片文件
> - 外链模式**必须**手动配置 `photos` 数组,至少需要提供 `src` 字段
> - 建议为外链照片提供 `thumbnail` 缩略图以提升加载速度
## 图片格式建议
### 封面图片 (cover.jpg)
- **尺寸**800×600px4:3 比例)
- **格式**JPG (外链模式可支持更多格式)
- **大小**:建议 < 200KB
### 相册照片
- **格式**JPGJPEGPNGWebPGIFSVGAVIF
- **尺寸**建议最大宽度 1920px
- **优化**建议压缩后上传提升加载速度
## 布局选项
### 网格布局 (Grid)
```json
{
"layout": "grid",
"columns": 3
}
```
- 适合尺寸统一的照片
- 支持 2-4
- 照片会被裁剪为正方形
### 瀑布流布局 (Masonry)
```json
{
"layout": "masonry",
"columns": 3
}
```
- 适合不同尺寸的照片
- 保持照片原始比例
- 自动排列视觉效果更自然
## 示例相册
项目包含以下示例相册供参考
### AcgExample
- **本地图片模式**示例
- 展示如何使用本地图片创建相册
- 瀑布流布局3
### ExternalExample
- **外链图片模式**示例默认隐藏
- 展示如何使用外部图片链接
- 适合使用图床的场景
### HiddenExample
- **隐藏相册**示例
- 展示如何创建不在列表显示的相册
- 可通过直接访问 URL 查看
## 高级功能
### 文件名标签(实验性)
系统支持从文件名解析标签格式`基本名_标签1_标签2.ext`
```
photo_sunset_beach.jpg → 标签sunset, beach
```
### 隐藏相册
设置 `"hidden": true` 可以隐藏相册但仍可通过 URL 直接访问
```
访问:/albums/your-album-id/
```
## 常见问题
**Q: 为什么我的相册没有显示?**
A: 检查是否存在 `info.json` `cover.jpg`以及 `hidden` 是否设置为 `true`
**Q: 可以使用其他图片格式吗?**
A: 可以支持 JPGPNGWebPGIFSVGAVIF 等格式
**Q: 如何优化图片加载速度?**
A: 建议使用 WebP 等压缩率较高的格式压缩图片大小使用外链模式时设置缩略图
**Q: 如何更改相册排序?**
A: 相册按时间顺序展示可通过修改相册的 `date` 字段调整排序

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

View File

@@ -0,0 +1,9 @@
{
"title": "我的二次元摄影册 [No.1]",
"description": "二次元大户发家史",
"date": "2024-03-15",
"location": "中国辽宁大连",
"tags": ["摄影", "二次元", "合集"],
"layout": "masonry",
"columns": 3
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

View File

@@ -0,0 +1,9 @@
{
"title": "我的二次元摄影册 [No.2]",
"description": "二次元大户发家史",
"date": "2024-03-15",
"location": "中国辽宁大连",
"tags": ["摄影", "二次元", "合集"],
"layout": "masonry",
"columns": 3
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
public/images/diary/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

View File

@@ -0,0 +1,48 @@
---
title: 《圆圈正义》读后感:永不完美的道德理想与坚持热望
published: 2025-12-07
description: '阅读《圆圈正义》有感而发'
image: './freedom.png'
tags: [BOOK, 书评]
category: '读书笔记'
draft: false
lang: 'zh_CN'
---
>“我们能画出的圆圈总是不够圆,但没有人会因此想取消圆圈。”——《圆圈正义》
***《圆圈正义》***是罗翔老师一部深刻探讨法律、道德与正义的随笔集。他以一位刑法学教授兼公共知识分子的身份,既剖析社会现象,亦直面人心幽暗之处。全书处处闪耀着思辨光芒与真挚的人性关怀,尤其那核心隐喻“圆圈正义”,已成为理解现代性道德困境的重要意象。
# ***不完美的圆圈:理想与现实的永恒张力***
罗翔提出的 ***圆圈正义*** 堪称精妙——正义如同数学中“圆”的概念一样,客观存在却无法在现实中被完美绘制。正如法律永远只能趋近于绝对正义却无法全然达成,人性永远在神圣与幽暗之间挣扎。
这个隐喻警醒我们:*正义有其客观向度(如不杀人、尊重生命是普遍的道德直觉)*,却又在具体执行中充满复杂性与妥协。认识到这种 ***圆而不圆*** 的张力,恰是走出偏狭的道德自恋的第一步。
在阅读过程中我常常自省:我们常常以 **没有人能做到完美** 而放弃追求,又或因理想看似不可能而沮丧怠惰。
罗翔则指出:正因为圆不可画出完美的实体, **努力接近理想状态** 才拥有了道德意义。那些 **“虽不能至,心向往之”** 的坚持,恰是人性最珍贵的光芒。
# ***法律与人性的双重镜鉴***
书中最为深刻之处在于它同时照亮了法律与人性的双重维度:
- **法律的局限与勇气**:罗翔并不迷信法律万能,直言其难免带有权力的烙印与时代限制。然法律的公正实施,是阻止“人祸”的底线屏障。书中对刑法的解说并非仅灌输法条,而重在揭示刑罚背后的价值冲突与人道精神。
- **人性的复杂透视**:他拒绝简单的“性善论”或“性恶论”,而是坦诚直面人性中存在的黑暗冲动(如嫉妒、自私)与崇高可能(如同理心、良心召唤)。我们每个人都可能身处“强人”或“弱者”的位置,道德选择从来与角色无关。
## ***思想共振***
>道德不是简单地追求尽善尽美,而是要求我们尽量避免成为他人苦难的助力。
***——面对无法阻止的恶,至少保持沉默本身就是一种微弱的抵抗。***
>愤怒本身何尝不是一种礼物,它提醒我们内心尚未麻木。
***——关键在于愤怒之后:是滑向仇恨的深渊?还是反思、对话与行动的起点?***
>法律只针对人类有限的行为予以规制,其目的并非制造完人,而是阻止最坏的灾难发生。
***——拒绝将法律置于道德制高点,也拒绝放弃法律作为文明的最后堤坝。***
# ***在局限中仍举灯行走***
在当下社会思潮纷乱、公共讨论常流于偏颇撕裂的语境中,《圆圈正义》如同一盏温暖而清醒的灯火。它在提醒我们:真正的道德生活,不是幻想能一劳永逸画出一个完美的圆来宣告理想已实现,而是日复一日地拿起笔来,在现实的泥泞土地上,带着谦卑、审慎却又无比固执地,画下去。
圆圈难圆,然其理想不陨。正义如星辰,虽不可及,却足以为在黑夜中跋涉者导航。这或许是罗翔老师留给这个喧嚣时代最宝贵的精神馈赠。
:::note[总结]
看完不算舒服,有种被打碎又重组后更结实的感觉。强推给所有对生活、对社会、对自己还有点“困惑”和“不平”的人。
:::

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@@ -0,0 +1,48 @@
---
title: VASP使用教程 [1]
published: 2025-12-01
description: '一个vasp的教程'
image: ''
tags: [VASP, 化学]
category: 'VASP'
draft: false
lang: 'zh_CN'
---
# 一、VASP简介
VASPVienna Ab initio Simulation Package是一个基于密度泛函理论DFT的量子化学计算软件包用于计算材料的电子结构和性质。它广泛应用于材料科学、化学、物理等领域用于研究材料的电子结构、能带结构、光学性质、磁学性质等。
# 二、VASP输入文件
VASP的输入文件主要包括INCAR、POSCAR、POTCAR、KPOINTS等文件。
1. INCAR包含计算参数如交换关联能、电子收敛精度、离子收敛精度等。
2. POSCAR包含晶格结构和原子坐标用于描述材料的晶体结构。
3. POTCAR包含原子势函数用于描述材料的电子结构。
# 三、VASP计算流程
VASP的计算流程主要包括以下几个步骤
1. 准备输入文件根据需设置INCAR、POSCAR、POTCAR、KPOINTS等文件。
2. 运行VASP使用vasp运行计算。
3. 分析结果使用vasp提供的输出文件分析计算结果如能带结构、态密度等。
# 四、VASP计算实例
介绍VASP的计算流程。
# 五、Linux相关命令
:::note[三令五申]
这是我的最后通牒
:::
:::tip[三令五申]
这是我的最后通牒
:::
:::warning[三令五申]
这是我的最后通牒
:::

BIN
src/content/posts/vps/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
src/content/posts/vps/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/content/posts/vps/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,118 @@
---
title: VPS购买与部署
published: 2025-12-02
description: 'VPS从购买到使用'
image: './cover.png'
tags: [VPS, Server]
category: '服务器'
cover: './cover.png'
draft: false
lang: 'zh_CN'
---
# 服务商简介
*CloudCone*在2025年*Cyber Monday*期间上线了一系列美国低价VPS方案其中入门款年付仅为`9.99$`,提供洛杉矶机房*1Gbps*带宽,并提供默认***1个IPv4+3个IPv6地址***。作为成立于2017年的云服务商CloudCone隶属于Edge Centres与Multacom机房同属一家母公司长期在开发者圈内拥有较高关注度。
本次促销覆盖`美国洛杉矶``圣路易斯``雷斯顿`三个数据中心并区分SSD缓存与原生SSD硬盘两类方案让用户能根据存储性能需求自由选择。[CloudCone官网](https://www.cloudcone.com)CloudCone支持 PayPal 与 支付宝 支付
# 促销机器
| 机器名称 | CPU | 内存 | 硬盘 | 流量带宽 | 机房 | 价格 |
| :----: | :----: | :----: | :----: | :----: | :----: | :----:
| CM-25-VPS-1 | 1 core | 1GB | 50GBSSD缓存 | 1TB/月 @1Gbps | 洛杉矶 | $9.99/年 |
| CM-25-SSD-VPS-2 | 3 cores | 2GB | 30GBSSD | 4TB/月 @1Gbps | 洛杉矶、圣路易斯、雷斯顿 | $16.99/年起 |
| CM-25-SSD-VPS-3| 6 cores | 4GB | 60GBSSD | 5TB/月 @1Gbps | 洛杉矶、圣路易斯、雷斯顿 | $28.99/年起 |
:::tip[购买提醒]
默认1个IPv4+3个IPv6
提醒:不同套餐的硬盘类型与数据中心不同,购买前需注意区分。
:::
# 选购指南
## CloudCone促销方案亮点
- 年付低至9.99美元,适合轻量网站、测试环境、个人项目
- 多机房选择:洛杉矶、西海岸,圣路易斯、中心地区,雷斯顿、东海岸
- SSD与SSD缓存两种硬盘系列
- 支持支付宝与PayPal充值
- KVM架构更稳定
>这里选取满足需求的CM-25-VPS-1进行演示
## 购买流程
* 打开[CloudCone官网](https://www.cloudcone.com),点击右上角`Sign Up`按钮
注册新账号(~~身份信息可以不完全准确~~
* 点击`Checkout`,选择`PayPal``支付宝`先充值余额
* 选择`CM-25-VPS-1`,选择洛杉矶机房,点击`Add to Cart`
* 点击`Checkout`,确认订单信息,点击`Deploy`(然后等待部署)
>主页中如图显示即为完成
![插图](./1.png)
# 连接服务器
## 获取服务器信息
* 打开[CloudCone后台](https://www.cloudcone.com),重新设置`root`账户密码
查看服务器IP地址需要注意的是IPV6地址需要在后台手动申请
* 打开任意一款ssh工具这里用Xshell演示
>如下填写
>![插图](./2.png)
>![插图](./3.png)
配置完成点击连接,弹出窗口选保存密钥即可。
## 配置基础环境
* 更新系统软件包
```bash
sudo apt update #这个命令会更新软件包列表,让系统知道有哪些软件包可以更新。
sudo apt upgrade --only-upgrade #这个命令会安装所有可用的软件包更新。
```
* 检查有没有安装VIM主要是我习惯用vim编辑器了Ubuntu是默认自带nano的
```bash
vim --version
```
* 没有显示版本就安装
```bash
sudo apt install vim
```
* 安装wget
```bash
sudo apt install wget
```
到这里服务器的购买和访问就已经告一段落了,接下来就是部署你需要的服务了。
后续的文章,我会部署一些好玩的项目,有缘再见。
# 常见问答Q&A
## CloudCone的9.99美元套餐适合做什么?
适合部署轻量博客、反向代理、小型项目、监控节点等低资源消耗应用。1GB内存+1TB流量对于基础使用已经足够。
## SSD缓存与SSD方案有什么区别
SSD缓存依赖缓存层加速整体读写性能不及原生SSD但容量通常更大、价格更便宜。若对磁盘性能敏感建议选择SSD系列。
## CloudCone是否支持国内用户付款
支持CloudCone提供支付宝充值也支持PayPal国内用户使用无障碍。
## 多机房之间有什么差别?
* 洛杉矶CloudCone主力机房网络覆盖较广
* 圣路易斯:美国中部,访问延迟均衡
* 雷斯顿:美国东部节点,适合面向欧美用户的业务
根据目标用户群选择更合适的数据中心即可。
:::note[网络测试信息]
美国 洛杉矶Los Angeles, CA
测试ip148.135.114.94
测速页https://lg-la.us.cloudc.one/
美国 圣路易斯St. Louis, MO
测试ip66.154.118.2
测速页https://lg-stl.us.cloudc.one/
美国 雷斯顿Reston, VA
测试ip66.154.126.2
测速页https://lg-rstn.us.cloudc.one/

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

51
src/content/spec/about.md Normal file
View File

@@ -0,0 +1,51 @@
:::note[生猛海鲜の小屋导航]
[ 主页 | 档案 📓 | 链接 📖 | 相册 🖼️ | 追番 🎞️ | 项目 🚀 | 知识库 🧠 | 轨迹 ⏳ | 等等 📝 ]
:::
# 📓 博客 (Blog)
* **内容:** 技术笔记 | 行业观察 | 学习心得 | 工具评测 | 生活杂感。
* **目标:** 记录专业思考与系统性总结分享。
* **特点:** 主题驱动 | 逻辑优先 | 技术/非技术并存。
* **实例主题:**
* `[VASP计算手册]`
* `[科研绘图]`
* `[二次元摄影教学]`
# 📖 日记 (Journal / Logs)
* **内容:** 日常片段 | 临时想法 | 读书摘记 | 学习反思 | 心得随笔 | *(可选)加密日志*
* **目标:** 快速捕捉q生活与思考碎片用于个人沉淀。
* **特点:** 时间流驱动 | 内容更具即兴性 | 部分笔记限时可见或私密。
* **更新频率:** `[eg: 日更 / 周更 / 有想法时]`
# 🖼️ 相册 (Albums)
* **内容:** 摄影作品 | 旅行记录 | 生活片段截图 | 可视化项目成果。
* **目标:** 视觉化存档 and 选择性分享。
* **特点:** 主题分类管理 | 按照时间组织 | 附加标题或简述 | 精选筛选。
:::tip[特色界面]
***| 追番 🎞️ | 项目 🚀 | 知识库 🧠 | 轨迹 ⏳ |***
:::
# 🎞️ 正在追番 (Anime/TV Tracker)
* **内容:**
* 当前 **追踪清单** (Title - Season)
* 单集/整体 **观剧状态标记** (👁️🗨️ 在看 / ▶️ 追番中 / ✓ 已完结 / ❌ 弃坑)
* *(可选)* 单集 **快速简评** / 槽点记录
* *(可选)* **深度长评** (可能发布在博客区)
* **目标:** 记录个人娱乐消费进度与偏好, 作为兴趣索引。
# 🚀 项目集 (Projects Portfolio)
* **核心展示项:**
* **暂未公开** 项目 (🔒)
* **目标:** 系统性展示项目经验、技术栈应用与问题解决能力。
# 🧠 知识库 (Knowledge Base / Digital Garden)
* **内容架构:**
* 结构化技术统计
* 命令速查手册 / API备忘
* 精选资源集合
* 阅读笔记 / 书摘精华
* 工作流优化 (工具链)
# ⏳ 人生轨迹 / NOW (Timeline / Now Page)
* **目标:** 提供背景上下文,清晰定义个人发展路径与现状状态。

55
src/data/anime.ts Normal file
View File

@@ -0,0 +1,55 @@
// 本地番剧数据配置
export type AnimeItem = {
title: string;
status: "watching" | "completed" | "planned";
rating: number;
cover: string;
description: string;
episodes: string;
year: string;
genre: string[];
studio: string;
link: string;
progress: number;
totalEpisodes: number;
startDate: string;
endDate: string;
};
const localAnimeList: AnimeItem[] = [
{
title: "Lycoris Recoil",
status: "completed",
rating: 9.8,
cover: "/assets/anime/lkls.webp",
description: "Girl's gunfight",
episodes: "12 episodes",
year: "2022",
genre: ["Action", "Slice of life"],
studio: "A-1 Pictures",
link: "https://www.bilibili.com/bangumi/media/md28338623",
progress: 12,
totalEpisodes: 12,
startDate: "2022-07",
endDate: "2022-09",
},
{
title: "名侦探柯南",
status: "watching",
rating: 9.7,
cover: "/assets/anime/mztkn.webp",
description: "名侦探",
episodes: "12 episodes",
year: "1996",
genre: ["推理", "悬疑"],
studio: "TMS Entertainment",
link: "https://www.bilibili.com/bangumi/media/md28228775",
progress: 1194,
totalEpisodes: 1241,
startDate: "1996-01",
endDate: "Unkown",
},
];
export default localAnimeList;

82
src/data/projects.ts Normal file
View File

@@ -0,0 +1,82 @@
// Project data configuration file
// Used to manage data for the project display page
export interface Project {
id: string;
title: string;
description: string;
image: string;
category: "web" | "mobile" | "desktop" | "other";
techStack: string[];
status: "completed" | "in-progress" | "planned";
liveDemo?: string;
sourceCode?: string;
startDate: string;
endDate?: string;
featured?: boolean;
tags?: string[];
visitUrl?: string; // 添加前往项目链接字段
}
export const projectsData: Project[] = [
// {
// id: "mizuki-blog",
// title: "Mizuki Blog Theme",
// description:
// "Modern blog theme developed based on the Astro framework, supporting multilingual, dark mode, and responsive design features.",
// image: "",
// category: "web",
// techStack: ["Astro", "TypeScript", "Tailwind CSS", "Svelte"],
// status: "completed",
// liveDemo: "https://blog.example.com",
// sourceCode: "https://github.com/example/mizuki", // 更改为GitHub链接
// visitUrl: "https://blog.example.com", // 添加前往项目链接
// startDate: "2024-01-01",
// endDate: "2024-06-01",
// featured: true,
// tags: ["Blog", "Theme", "Open Source"],
// },
];
// Get project statistics
export const getProjectStats = () => {
const total = projectsData.length;
const completed = projectsData.filter((p) => p.status === "completed").length;
const inProgress = projectsData.filter(
(p) => p.status === "in-progress",
).length;
const planned = projectsData.filter((p) => p.status === "planned").length;
return {
total,
byStatus: {
completed,
inProgress,
planned,
},
};
};
// Get projects by category
export const getProjectsByCategory = (category?: string) => {
if (!category || category === "all") {
return projectsData;
}
return projectsData.filter((p) => p.category === category);
};
// Get featured projects
export const getFeaturedProjects = () => {
return projectsData.filter((p) => p.featured);
};
// Get all tech stacks
export const getAllTechStack = () => {
const techSet = new Set<string>();
projectsData.forEach((project) => {
project.techStack.forEach((tech) => {
techSet.add(tech);
});
});
return Array.from(techSet).sort();
};

310
src/data/skills.ts Normal file
View File

@@ -0,0 +1,310 @@
// Skill data configuration file
// Used to manage data for the skill display page
export interface Skill {
id: string;
name: string;
description: string;
icon: string; // Iconify icon name
category: "frontend" | "backend" | "database" | "tools" | "other";
level: "beginner" | "intermediate" | "advanced" | "expert";
experience: {
years: number;
months: number;
};
projects?: string[]; // Related project IDs
certifications?: string[];
color?: string; // Skill card theme color
}
export const skillsData: Skill[] = [
// Frontend Skills
{
id: "javascript",
name: "JavaScript",
description:
"Modern JavaScript development, including ES6+ syntax, asynchronous programming, and modular development.",
icon: "logos:javascript",
category: "frontend",
level: "advanced",
experience: { years: 0, months: 6 },
projects: ["mizuki-blog", "portfolio-website", "data-visualization-tool"],
color: "#F7DF1E",
},
{
id: "typescript",
name: "TypeScript",
description:
"A type-safe superset of JavaScript that enhances code quality and development efficiency.",
icon: "logos:typescript-icon",
category: "frontend",
level: "advanced",
experience: { years: 0, months: 8 },
projects: ["mizuki-blog", "portfolio-website", "task-manager-app"],
color: "#3178C6",
},
{
id: "react",
name: "React",
description:
"A JavaScript library for building user interfaces, including Hooks, Context, and state management.",
icon: "logos:react",
category: "frontend",
level: "advanced",
experience: { years: 0, months: 10 },
projects: ["portfolio-website", "task-manager-app"],
color: "#61DAFB",
},
{
id: "vue",
name: "Vue.js",
description:
"A progressive JavaScript framework that is easy to learn and use, suitable for rapid development.",
icon: "logos:vue",
category: "frontend",
level: "intermediate",
experience: { years: 0, months: 8 },
projects: ["data-visualization-tool"],
color: "#4FC08D",
},
{
id: "nextjs",
name: "Next.js",
description:
"A production-level React framework supporting SSR, SSG, and full-stack development.",
icon: "logos:nextjs-icon",
category: "frontend",
level: "intermediate",
experience: { years: 0, months: 4 },
projects: ["e-commerce-frontend", "blog-platform"],
color: "#616161", // 更改为深灰色,避免纯黑色
},
{
id: "astro",
name: "Astro",
description:
"A modern static site generator supporting multi-framework integration and excellent performance.",
icon: "logos:astro-icon",
category: "frontend",
level: "advanced",
experience: { years: 0, months: 2 },
projects: ["mizuki-blog"],
color: "#FF5D01",
},
{
id: "vite",
name: "Vite",
description:
"Next-generation frontend build tool with fast cold starts and hot updates.",
icon: "logos:vitejs",
category: "frontend",
level: "intermediate",
experience: { years: 1, months: 2 },
projects: ["vue-project", "react-project"],
color: "#646CFF",
},
// Backend Skills
{
id: "python",
name: "Python",
description:
"A general-purpose programming language suitable for web development, data analysis, machine learning, and more.",
icon: "logos:python",
category: "backend",
level: "intermediate",
experience: { years: 2, months: 10 },
color: "#3776AB",
},
{
id: "cpp",
name: "C++",
description:
"A high-performance systems programming language widely used in game development, system software, and embedded development.",
icon: "logos:c-plusplus",
category: "backend",
level: "intermediate",
experience: { years: 0, months: 4 },
projects: ["game-engine", "system-optimization"],
color: "#00599C",
},
{
id: "c",
name: "C",
description:
"A low-level systems programming language, the foundation for operating systems and embedded systems development.",
icon: "logos:c",
category: "backend",
level: "intermediate",
experience: { years: 0, months: 3 },
projects: ["embedded-system", "kernel-module"],
color: "#A8B9CC",
},
{
id: "django",
name: "Django",
description:
"A high-level Python web framework with rapid development and clean, pragmatic design.",
icon: "logos:django-icon",
category: "backend",
level: "beginner",
experience: { years: 0, months: 6 },
projects: ["blog-backend"],
color: "#092E20",
},
// Database Skills
{
id: "mysql",
name: "MySQL",
description:
"The world's most popular open-source relational database management system, widely used in web applications.",
icon: "logos:mysql-icon",
category: "database",
level: "advanced",
experience: { years: 2, months: 6 },
projects: ["e-commerce-platform", "blog-system"],
color: "#4479A1",
},
// Tools
{
id: "git",
name: "Git",
description:
"A distributed version control system, an essential tool for code management and team collaboration.",
icon: "logos:git-icon",
category: "tools",
level: "advanced",
experience: { years: 3, months: 0 },
color: "#F05032",
},
{
id: "vscode",
name: "VS Code",
description:
"A lightweight but powerful code editor with a rich plugin ecosystem.",
icon: "logos:visual-studio-code",
category: "tools",
level: "expert",
experience: { years: 3, months: 6 },
color: "#007ACC",
},
{
id: "pycharm",
name: "PyCharm",
description:
"A professional Python IDE by JetBrains providing intelligent code analysis and debugging features.",
icon: "logos:pycharm",
category: "tools",
level: "intermediate",
experience: { years: 1, months: 4 },
projects: ["python-web-app", "data-analysis"],
color: "#21D789",
},
{
id: "docker",
name: "Docker",
description:
"A containerization platform that simplifies application deployment and environment management.",
icon: "logos:docker-icon",
category: "tools",
level: "intermediate",
experience: { years: 1, months: 0 },
color: "#2496ED",
},
{
id: "nginx",
name: "Nginx",
description: "A high-performance web server and reverse proxy server.",
icon: "logos:nginx",
category: "tools",
level: "intermediate",
experience: { years: 1, months: 2 },
projects: ["web-server-config", "load-balancer"],
color: "#009639",
},
{
id: "linux",
name: "Linux",
description:
"An open-source operating system, the preferred choice for server deployment and development environments.",
icon: "logos:linux-tux",
category: "tools",
level: "intermediate",
experience: { years: 2, months: 0 },
projects: ["server-management", "shell-scripting"],
color: "#FCC624",
},
{
id: "photoshop",
name: "Photoshop",
description: "Professional image editing and design software.",
icon: "logos:adobe-photoshop",
category: "tools",
level: "intermediate",
experience: { years: 2, months: 6 },
projects: ["ui-design", "image-processing"],
color: "#31A8FF",
},
// Other Skills
{
id: "photography",
name: "photography",
description:
"二次元风光摄影.",
icon: "material-symbols:photo-camera-outline-rounded",
category: "other",
level: "advanced",
experience: { years: 2, months: 4 },
projects: ["modern-api"],
color: "#E10098",
},
];
// Get skill statistics
export const getSkillStats = () => {
const total = skillsData.length;
const byLevel = {
beginner: skillsData.filter((s) => s.level === "beginner").length,
intermediate: skillsData.filter((s) => s.level === "intermediate").length,
advanced: skillsData.filter((s) => s.level === "advanced").length,
expert: skillsData.filter((s) => s.level === "expert").length,
};
const byCategory = {
frontend: skillsData.filter((s) => s.category === "frontend").length,
backend: skillsData.filter((s) => s.category === "backend").length,
database: skillsData.filter((s) => s.category === "database").length,
tools: skillsData.filter((s) => s.category === "tools").length,
other: skillsData.filter((s) => s.category === "other").length,
};
return { total, byLevel, byCategory };
};
// Get skills by category
export const getSkillsByCategory = (category?: string) => {
if (!category || category === "all") {
return skillsData;
}
return skillsData.filter((s) => s.category === category);
};
// Get advanced skills
export const getAdvancedSkills = () => {
return skillsData.filter(
(s) => s.level === "advanced" || s.level === "expert",
);
};
// Calculate total years of experience
export const getTotalExperience = () => {
const totalMonths = skillsData.reduce((total, skill) => {
return total + skill.experience.years * 12 + skill.experience.months;
}, 0);
return {
years: Math.floor(totalMonths / 12),
months: totalMonths % 12,
};
};

110
src/data/timeline.ts Normal file
View File

@@ -0,0 +1,110 @@
// Timeline data configuration file
// Used to manage data for the timeline page
export interface TimelineItem {
id: string;
title: string;
description: string;
type: "education" | "work" | "project" | "achievement";
startDate: string;
endDate?: string; // If empty, it means current
location?: string;
organization?: string;
position?: string;
skills?: string[];
achievements?: string[];
links?: {
name: string;
url: string;
type: "website" | "certificate" | "project" | "other";
}[];
icon?: string; // Iconify icon name
color?: string;
featured?: boolean;
}
export const timelineData: TimelineItem[] = [
{
id: "current-study",
title: "Studying Chemical Engineering",
description:
"Currently studying Chemical Engineering.",
type: "education",
startDate: "2022-09-01",
location: "Dalian",
organization: "Dalian University of Technology",
// skills: ["Java", "Python", "JavaScript", "HTML/CSS", "MySQL"],
// achievements: [
// "Current GPA: 3.6/4.0",
// "Completed data structures and algorithms course project",
// "Participated in multiple course project developments",
// ],
icon: "material-symbols:school",
color: "#059669",
featured: true,
},
];
// Get timeline statistics
export const getTimelineStats = () => {
const total = timelineData.length;
const byType = {
education: timelineData.filter((item) => item.type === "education").length,
work: timelineData.filter((item) => item.type === "work").length,
project: timelineData.filter((item) => item.type === "project").length,
achievement: timelineData.filter((item) => item.type === "achievement")
.length,
};
return { total, byType };
};
// Get timeline items by type
export const getTimelineByType = (type?: string) => {
if (!type || type === "all") {
return timelineData.sort(
(a, b) =>
new Date(b.startDate).getTime() - new Date(a.startDate).getTime(),
);
}
return timelineData
.filter((item) => item.type === type)
.sort(
(a, b) =>
new Date(b.startDate).getTime() - new Date(a.startDate).getTime(),
);
};
// Get featured timeline items
export const getFeaturedTimeline = () => {
return timelineData
.filter((item) => item.featured)
.sort(
(a, b) =>
new Date(b.startDate).getTime() - new Date(a.startDate).getTime(),
);
};
// Get current ongoing items
export const getCurrentItems = () => {
return timelineData.filter((item) => !item.endDate);
};
// Calculate total work experience
export const getTotalWorkExperience = () => {
const workItems = timelineData.filter((item) => item.type === "work");
let totalMonths = 0;
workItems.forEach((item) => {
const startDate = new Date(item.startDate);
const endDate = item.endDate ? new Date(item.endDate) : new Date();
const diffTime = Math.abs(endDate.getTime() - startDate.getTime());
const diffMonths = Math.ceil(diffTime / (1000 * 60 * 60 * 24 * 30));
totalMonths += diffMonths;
});
return {
years: Math.floor(totalMonths / 12),
months: totalMonths % 12,
};
};