diff --git a/.env.example b/.env.example index e69de29..c151188 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,49 @@ +# Mizuki 博客环境变量配置示例 +# 复制此文件为 .env 并根据需要填写实际值 + +# ============================================ +# 内容仓库配置 (代码内容分离) +# 项目地址:https://github.com/matsuzaka-yuki/Mizuki-Content +# ============================================ + +# 是否启用内容分离功能 (true/false) +# true: 启用内容分离,从独立仓库同步内容 +# false: 禁用内容分离,使用本地内容 (默认模式) +# 注意: 如果不使用内容分离功能,可以注释掉或设置为 false +ENABLE_CONTENT_SYNC=true + +# 内容仓库的 Git URL (仅在 ENABLE_CONTENT_SYNC=true 时需要) +# 支持 HTTPS 和 SSH 两种方式: +# HTTPS: https://github.com/your-username/Mizuki-Content.git +# SSH: git@github.com:your-username/Mizuki-Content.git +CONTENT_REPO_URL=https://gitea.namyki.top/namyki/BlogContent.git +USE_SUBMODULE=true + +# 内容目录路径 (相对于项目根目录) +# 默认: ./content 一般无需改动 +# CONTENT_DIR=./content + +# ============================================ +# 自动构建触发配置 (内容仓库更新时) +# ============================================ + +# 问题: 内容仓库更新不会自动触发代码仓库的部署 +# 解决: 配置自动触发机制,推荐使用 Repository Dispatch +# 详见: docs/AUTO_BUILD_TRIGGER.md (5 步快速配置) + +# ============================================ +# 统计与分析 +# ============================================ + +# Umami API 密钥,用于访问 Umami 统计数据 +# 如果在 config.ts 中启用了 Umami,建议在此配置 API 密钥 +#UMAMI_API_KEY=your_umami_api_key_here + +# ============================================ +# 安全配置 +# ============================================ + +# bcrypt 盐值轮数,用于加密文章密码 +# 值越大越安全,但构建时间越长 +# 推荐值:10-14(默认:12) +BCRYPT_SALT_ROUNDS=12 diff --git a/content b/content deleted file mode 160000 index fb2a4f0..0000000 --- a/content +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fb2a4f05d29b3ca6f8e0a5545c7c553a41961e4a diff --git a/public/images/albums/ExternalExample/info.json b/public/images/albums/ExternalExample/info.json deleted file mode 100644 index a67d8c8..0000000 --- a/public/images/albums/ExternalExample/info.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "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 - } - ] -} diff --git a/public/images/albums/README.md b/public/images/albums/README.md deleted file mode 100644 index 9b73a90..0000000 --- a/public/images/albums/README.md +++ /dev/null @@ -1,211 +0,0 @@ -# 相册功能使用说明 - -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×600px(4:3 比例) -- **格式**:JPG (外链模式可支持更多格式) -- **大小**:建议 < 200KB - -### 相册照片 -- **格式**:JPG、JPEG、PNG、WebP、GIF、SVG、AVIF -- **尺寸**:建议最大宽度 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: 可以,支持 JPG、PNG、WebP、GIF、SVG、AVIF 等格式。 - -**Q: 如何优化图片加载速度?** -A: 建议使用 WebP 等压缩率较高的格式压缩图片大小。使用外链模式时设置缩略图。 - -**Q: 如何更改相册排序?** -A: 相册按时间顺序展示,可通过修改相册的 `date` 字段调整排序。 diff --git a/public/images/albums/photograph_1/cover.jpg b/public/images/albums/photograph_1/cover.jpg deleted file mode 100644 index d797c33..0000000 Binary files a/public/images/albums/photograph_1/cover.jpg and /dev/null differ diff --git a/public/images/albums/photograph_1/info.json b/public/images/albums/photograph_1/info.json deleted file mode 100644 index c776872..0000000 --- a/public/images/albums/photograph_1/info.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "我的二次元摄影册 [No.1]", - "description": "二次元大户发家史", - "date": "2024-03-15", - "location": "中国辽宁大连", - "tags": ["摄影", "二次元", "合集"], - "layout": "masonry", - "columns": 3 -} diff --git a/public/images/albums/photograph_1/photos-10.jpg b/public/images/albums/photograph_1/photos-10.jpg deleted file mode 100644 index b719109..0000000 Binary files a/public/images/albums/photograph_1/photos-10.jpg and /dev/null differ diff --git a/public/images/albums/photograph_1/photos-13.jpg b/public/images/albums/photograph_1/photos-13.jpg deleted file mode 100644 index 88fa565..0000000 Binary files a/public/images/albums/photograph_1/photos-13.jpg and /dev/null differ diff --git a/public/images/albums/photograph_1/photos-18.jpg b/public/images/albums/photograph_1/photos-18.jpg deleted file mode 100644 index f4379e9..0000000 Binary files a/public/images/albums/photograph_1/photos-18.jpg and /dev/null differ diff --git a/public/images/albums/photograph_1/photos-3.jpg b/public/images/albums/photograph_1/photos-3.jpg deleted file mode 100644 index a5b67df..0000000 Binary files a/public/images/albums/photograph_1/photos-3.jpg and /dev/null differ diff --git a/public/images/albums/photograph_1/photos-6.jpg b/public/images/albums/photograph_1/photos-6.jpg deleted file mode 100644 index a0522dc..0000000 Binary files a/public/images/albums/photograph_1/photos-6.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/cover.jpg b/public/images/albums/photograph_2/cover.jpg deleted file mode 100644 index c0e15aa..0000000 Binary files a/public/images/albums/photograph_2/cover.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/info.json b/public/images/albums/photograph_2/info.json deleted file mode 100644 index 461c5dc..0000000 --- a/public/images/albums/photograph_2/info.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "title": "我的二次元摄影册 [No.2]", - "description": "二次元大户发家史", - "date": "2024-03-15", - "location": "中国辽宁大连", - "tags": ["摄影", "二次元", "合集"], - "layout": "masonry", - "columns": 3 -} diff --git a/public/images/albums/photograph_2/photos-1.jpg b/public/images/albums/photograph_2/photos-1.jpg deleted file mode 100644 index 75af3d1..0000000 Binary files a/public/images/albums/photograph_2/photos-1.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-11.jpg b/public/images/albums/photograph_2/photos-11.jpg deleted file mode 100644 index a409805..0000000 Binary files a/public/images/albums/photograph_2/photos-11.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-12.jpg b/public/images/albums/photograph_2/photos-12.jpg deleted file mode 100644 index 1a472ea..0000000 Binary files a/public/images/albums/photograph_2/photos-12.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-15.jpg b/public/images/albums/photograph_2/photos-15.jpg deleted file mode 100644 index e759b63..0000000 Binary files a/public/images/albums/photograph_2/photos-15.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-16.jpg b/public/images/albums/photograph_2/photos-16.jpg deleted file mode 100644 index 08f9f02..0000000 Binary files a/public/images/albums/photograph_2/photos-16.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-17.jpg b/public/images/albums/photograph_2/photos-17.jpg deleted file mode 100644 index 8183de4..0000000 Binary files a/public/images/albums/photograph_2/photos-17.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-19.jpg b/public/images/albums/photograph_2/photos-19.jpg deleted file mode 100644 index 11b8dae..0000000 Binary files a/public/images/albums/photograph_2/photos-19.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-2.jpg b/public/images/albums/photograph_2/photos-2.jpg deleted file mode 100644 index 87dbcd2..0000000 Binary files a/public/images/albums/photograph_2/photos-2.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-4.jpg b/public/images/albums/photograph_2/photos-4.jpg deleted file mode 100644 index 8179b61..0000000 Binary files a/public/images/albums/photograph_2/photos-4.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-5.jpg b/public/images/albums/photograph_2/photos-5.jpg deleted file mode 100644 index dd73b48..0000000 Binary files a/public/images/albums/photograph_2/photos-5.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-7.jpg b/public/images/albums/photograph_2/photos-7.jpg deleted file mode 100644 index ab50ebd..0000000 Binary files a/public/images/albums/photograph_2/photos-7.jpg and /dev/null differ diff --git a/public/images/albums/photograph_2/photos-9.jpg b/public/images/albums/photograph_2/photos-9.jpg deleted file mode 100644 index 1250979..0000000 Binary files a/public/images/albums/photograph_2/photos-9.jpg and /dev/null differ diff --git a/public/images/device/mi14p.jpg b/public/images/device/mi14p.jpg deleted file mode 100644 index ce45c10..0000000 Binary files a/public/images/device/mi14p.jpg and /dev/null differ diff --git a/public/images/device/mt3000.png b/public/images/device/mt3000.png deleted file mode 100644 index e962c0e..0000000 Binary files a/public/images/device/mt3000.png and /dev/null differ diff --git a/public/images/device/oneplus13t.png b/public/images/device/oneplus13t.png deleted file mode 100644 index ae89d62..0000000 Binary files a/public/images/device/oneplus13t.png and /dev/null differ diff --git a/public/images/diary/1.jpg b/public/images/diary/1.jpg deleted file mode 100644 index 4e06a40..0000000 Binary files a/public/images/diary/1.jpg and /dev/null differ diff --git a/public/images/diary/sakura.jpg b/public/images/diary/sakura.jpg deleted file mode 100644 index 43dfdb8..0000000 Binary files a/public/images/diary/sakura.jpg and /dev/null differ diff --git a/src/config.ts b/src/config.ts index 0168a8d..f311a33 100644 --- a/src/config.ts +++ b/src/config.ts @@ -22,7 +22,7 @@ const SITE_TIMEZONE = 8; //设置你的网站时区 from -12 to 12 default in UT export const siteConfig: SiteConfig = { title: "海の小屋", subtitle: "工于至诚,学以致用", - siteURL: "https://blog.namyki.com/", // 请替换为你的站点URL,以斜杠结尾 + siteURL: "https://astro.namyki.com/", // 请替换为你的站点URL,以斜杠结尾 siteStartDate: "2025-12-01", // 站点开始运行日期,用于站点统计组件计算运行天数 timeZone: SITE_TIMEZONE, @@ -190,9 +190,9 @@ export const siteConfig: SiteConfig = { }, cjkFont: { // 中日韩字体 - 作为回退字体 - fontFamily: "萝莉体 第二版", + fontFamily: "futomaru401", fontWeight: "500", - localFonts: ["萝莉体 第二版.ttf"], + localFonts: ["futomaru401.ttf"], enableCompress: true, // 启用字体子集优化,减少字体文件大小 }, }, diff --git a/src/content/posts/readnote/freedom.md b/src/content/posts/readnote/freedom.md deleted file mode 100644 index 289eca0..0000000 --- a/src/content/posts/readnote/freedom.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: 《圆圈正义》读后感:永不完美的道德理想与坚持热望 -published: 2025-12-07 -description: '阅读《圆圈正义》有感而发' -image: './freedom.png' -tags: [BOOK, 书评] -category: '读书笔记' -draft: false -lang: 'zh_CN' ---- - ->“我们能画出的圆圈总是不够圆,但没有人会因此想取消圆圈。”——《圆圈正义》 - -***《圆圈正义》***是罗翔老师一部深刻探讨法律、道德与正义的随笔集。他以一位刑法学教授兼公共知识分子的身份,既剖析社会现象,亦直面人心幽暗之处。全书处处闪耀着思辨光芒与真挚的人性关怀,尤其那核心隐喻“圆圈正义”,已成为理解现代性道德困境的重要意象。 - -# ***不完美的圆圈:理想与现实的永恒张力*** -罗翔提出的 ***圆圈正义*** 堪称精妙——正义如同数学中“圆”的概念一样,客观存在却无法在现实中被完美绘制。正如法律永远只能趋近于绝对正义却无法全然达成,人性永远在神圣与幽暗之间挣扎。 - -这个隐喻警醒我们:*正义有其客观向度(如不杀人、尊重生命是普遍的道德直觉)*,却又在具体执行中充满复杂性与妥协。认识到这种 ***圆而不圆*** 的张力,恰是走出偏狭的道德自恋的第一步。 - -在阅读过程中我常常自省:我们常常以 **没有人能做到完美** 而放弃追求,又或因理想看似不可能而沮丧怠惰。 - -罗翔则指出:正因为圆不可画出完美的实体, **努力接近理想状态** 才拥有了道德意义。那些 **“虽不能至,心向往之”** 的坚持,恰是人性最珍贵的光芒。 - -# ***法律与人性的双重镜鉴*** -书中最为深刻之处在于它同时照亮了法律与人性的双重维度: -- **法律的局限与勇气**:罗翔并不迷信法律万能,直言其难免带有权力的烙印与时代限制。然法律的公正实施,是阻止“人祸”的底线屏障。书中对刑法的解说并非仅灌输法条,而重在揭示刑罚背后的价值冲突与人道精神。 -- **人性的复杂透视**:他拒绝简单的“性善论”或“性恶论”,而是坦诚直面人性中存在的黑暗冲动(如嫉妒、自私)与崇高可能(如同理心、良心召唤)。我们每个人都可能身处“强人”或“弱者”的位置,道德选择从来与角色无关。 - -## ***思想共振*** - ->道德不是简单地追求尽善尽美,而是要求我们尽量避免成为他人苦难的助力。 -***——面对无法阻止的恶,至少保持沉默本身就是一种微弱的抵抗。*** - ->愤怒本身何尝不是一种礼物,它提醒我们内心尚未麻木。 -***——关键在于愤怒之后:是滑向仇恨的深渊?还是反思、对话与行动的起点?*** - ->法律只针对人类有限的行为予以规制,其目的并非制造完人,而是阻止最坏的灾难发生。 -***——拒绝将法律置于道德制高点,也拒绝放弃法律作为文明的最后堤坝。*** - -# ***在局限中仍举灯行走*** -在当下社会思潮纷乱、公共讨论常流于偏颇撕裂的语境中,《圆圈正义》如同一盏温暖而清醒的灯火。它在提醒我们:真正的道德生活,不是幻想能一劳永逸画出一个完美的圆来宣告理想已实现,而是日复一日地拿起笔来,在现实的泥泞土地上,带着谦卑、审慎却又无比固执地,画下去。 - -圆圈难圆,然其理想不陨。正义如星辰,虽不可及,却足以为在黑夜中跋涉者导航。这或许是罗翔老师留给这个喧嚣时代最宝贵的精神馈赠。 - -:::note[总结] -看完不算舒服,有种被打碎又重组后更结实的感觉。强推给所有对生活、对社会、对自己还有点“困惑”和“不平”的人。 -::: \ No newline at end of file diff --git a/src/content/posts/readnote/freedom.png b/src/content/posts/readnote/freedom.png deleted file mode 100644 index 38f674c..0000000 Binary files a/src/content/posts/readnote/freedom.png and /dev/null differ diff --git a/src/content/posts/vasp/VASP.md b/src/content/posts/vasp/VASP.md deleted file mode 100644 index 683e9dc..0000000 --- a/src/content/posts/vasp/VASP.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: VASP使用教程 [1] -published: 2025-12-01 -description: '一个vasp的教程' -image: '' -tags: [VASP, 化学] -category: 'VASP' -draft: false -lang: 'zh_CN' ---- - -# 一、VASP简介 - -VASP(Vienna 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[三令五申] -这是我的最后通牒 -::: \ No newline at end of file diff --git a/src/content/posts/vps/1.png b/src/content/posts/vps/1.png deleted file mode 100644 index a271b93..0000000 Binary files a/src/content/posts/vps/1.png and /dev/null differ diff --git a/src/content/posts/vps/2.png b/src/content/posts/vps/2.png deleted file mode 100644 index 07f25fc..0000000 Binary files a/src/content/posts/vps/2.png and /dev/null differ diff --git a/src/content/posts/vps/3.png b/src/content/posts/vps/3.png deleted file mode 100644 index 573110f..0000000 Binary files a/src/content/posts/vps/3.png and /dev/null differ diff --git a/src/content/posts/vps/VPS.md b/src/content/posts/vps/VPS.md deleted file mode 100644 index 9d98816..0000000 --- a/src/content/posts/vps/VPS.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -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 | 50GB(SSD缓存) | 1TB/月 @1Gbps | 洛杉矶 | $9.99/年 | -| CM-25-SSD-VPS-2 | 3 cores | 2GB | 30GB(SSD) | 4TB/月 @1Gbps | 洛杉矶、圣路易斯、雷斯顿 | $16.99/年起 | -| CM-25-SSD-VPS-3| 6 cores | 4GB | 60GB(SSD) | 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) - -测试ip:148.135.114.94 - -测速页:https://lg-la.us.cloudc.one/ - -美国 圣路易斯(St. Louis, MO) - -测试ip:66.154.118.2 - -测速页:https://lg-stl.us.cloudc.one/ - -美国 雷斯顿(Reston, VA) - -测试ip:66.154.126.2 - -测速页:https://lg-rstn.us.cloudc.one/ \ No newline at end of file diff --git a/src/content/posts/vps/cover.png b/src/content/posts/vps/cover.png deleted file mode 100644 index 926d3bc..0000000 Binary files a/src/content/posts/vps/cover.png and /dev/null differ diff --git a/src/content/spec/about.md b/src/content/spec/about.md deleted file mode 100644 index 9de4815..0000000 --- a/src/content/spec/about.md +++ /dev/null @@ -1,51 +0,0 @@ -:::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) -* **目标:** 提供背景上下文,清晰定义个人发展路径与现状状态。 \ No newline at end of file diff --git a/src/content/spec/friends.md b/src/content/spec/friends.md deleted file mode 100644 index e69de29..0000000 diff --git a/src/data/anime.ts b/src/data/anime.ts deleted file mode 100644 index cb0ccbd..0000000 --- a/src/data/anime.ts +++ /dev/null @@ -1,55 +0,0 @@ -// 本地番剧数据配置 -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; diff --git a/src/data/devices.ts b/src/data/devices.ts deleted file mode 100644 index 450a7ca..0000000 --- a/src/data/devices.ts +++ /dev/null @@ -1,28 +0,0 @@ -// 设备数据配置文件 - -export interface Device { - name: string; - image: string; - specs: string; - description: string; - link: string; -} - -// 设备类别类型,支持品牌和自定义类别 -export type DeviceCategory = { - [categoryName: string]: Device[]; -} & { - 自定义?: Device[]; -}; - -export const devicesData: DeviceCategory = { - Xiaomi: [ - { - name: "Xiaomi 14Pro", - image: "/images/device/mi14p.jpg", - specs: "Black / 12G + 256TB", - description: "Xiaomi 14 Pro,超越旗舰,超乎所想。", - link: "https://www.mi.com/xiaomi-14-pro", - }, - ], -}; diff --git a/src/data/diary.ts b/src/data/diary.ts deleted file mode 100644 index 2b61916..0000000 --- a/src/data/diary.ts +++ /dev/null @@ -1,98 +0,0 @@ -// 日记数据配置 -// 用于管理日记页面的数据 - -export interface DiaryItem { - id: number; - content: string; - date: string; - images?: string[]; - location?: string; - mood?: string; - tags?: string[]; -} - -// 示例日记数据 -const diaryData: DiaryItem[] = [ - // { - // id: 1, - // content: - // "The falling speed of cherry blossoms is five centimeters per second!", - // date: "2025-01-15T10:30:00Z", - // images: ["/images/diary/sakura.jpg", "/images/diary/1.jpg"], - // }, - // { - // id: 2, - // content: - // "The falling speed of cherry blossoms is five centimeters per second!", - // date: "2025-01-15T10:30:00Z", - // images: ["/images/diary/sakura.jpg", "/images/diary/1.jpg"], - // }, -]; - -// 获取日记统计数据 -export const getDiaryStats = () => { - const total = diaryData.length; - const hasImages = diaryData.filter( - (item) => item.images && item.images.length > 0, - ).length; - const hasLocation = diaryData.filter((item) => item.location).length; - const hasMood = diaryData.filter((item) => item.mood).length; - - return { - total, - hasImages, - hasLocation, - hasMood, - imagePercentage: Math.round((hasImages / total) * 100), - locationPercentage: Math.round((hasLocation / total) * 100), - moodPercentage: Math.round((hasMood / total) * 100), - }; -}; - -// 获取日记列表(按时间倒序) -export const getDiaryList = (limit?: number) => { - const sortedData = diaryData.sort( - (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(), - ); - - if (limit && limit > 0) { - return sortedData.slice(0, limit); - } - - return sortedData; -}; - -// 获取最新的日记 -export const getLatestDiary = () => { - return getDiaryList(1)[0]; -}; - -// 根据ID获取日记 -export const getDiaryById = (id: number) => { - return diaryData.find((item) => item.id === id); -}; - -// 获取包含图片的日记 -export const getDiaryWithImages = () => { - return diaryData.filter((item) => item.images && item.images.length > 0); -}; - -// 根据标签筛选日记 -export const getDiaryByTag = (tag: string) => { - return diaryData - .filter((item) => item.tags?.includes(tag)) - .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); -}; - -// 获取所有标签 -export const getAllTags = () => { - const tags = new Set(); - diaryData.forEach((item) => { - if (item.tags) { - item.tags.forEach((tag) => tags.add(tag)); - } - }); - return Array.from(tags).sort(); -}; - -export default diaryData; diff --git a/src/data/friends.ts b/src/data/friends.ts deleted file mode 100644 index f504b36..0000000 --- a/src/data/friends.ts +++ /dev/null @@ -1,95 +0,0 @@ -// 友情链接数据配置 -// 用于管理友情链接页面的数据 - -export interface FriendItem { - id: number; - title: string; - imgurl: string; - desc: string; - siteurl: string; - tags: string[]; -} - -// 友情链接数据 -export const friendsData: FriendItem[] = [ - { - id: 1, - title: "Astro", - imgurl: "https://avatars.githubusercontent.com/u/44914786?v=4&s=640", - desc: "The web framework for content-driven websites", - siteurl: "https://github.com/withastro/astro", - tags: ["Framework"], - }, - // { - // id: 2, - // title: "Mizuki Docs", - // imgurl: - // "http://q.qlogo.cn/headimg_dl?dst_uin=3231515355&spec=640&img_type=jpg", - // desc: "Mizuki User Manual", - // siteurl: "https://docs.mizuki.mysqil.com", - // tags: ["Docs"], - // }, - // { - // id: 3, - // title: "Vercel", - // imgurl: "https://avatars.githubusercontent.com/u/14985020?v=4&s=640", - // desc: "Develop. Preview. Ship.", - // siteurl: "https://vercel.com", - // tags: ["Hosting", "Cloud"], - // }, - // { - // id: 4, - // title: "Tailwind CSS", - // imgurl: "https://avatars.githubusercontent.com/u/67109815?v=4&s=640", - // desc: "A utility-first CSS framework for rapidly building custom designs", - // siteurl: "https://tailwindcss.com", - // tags: ["CSS", "Framework"], - // }, - // { - // id: 5, - // title: "TypeScript", - // imgurl: "https://avatars.githubusercontent.com/u/6154722?v=4&s=640", - // desc: "TypeScript is JavaScript with syntax for types", - // siteurl: "https://www.typescriptlang.org", - // tags: ["Language", "JavaScript"], - // }, - // { - // id: 6, - // title: "React", - // imgurl: "https://avatars.githubusercontent.com/u/6412038?v=4&s=640", - // desc: "A JavaScript library for building user interfaces", - // siteurl: "https://reactjs.org", - // tags: ["Framework", "JavaScript"], - // }, - // { - // id: 7, - // title: "GitHub", - // imgurl: "https://avatars.githubusercontent.com/u/9919?v=4&s=640", - // desc: "Where the world builds software", - // siteurl: "https://github.com", - // tags: ["Development", "Platform"], - // }, - // { - // id: 8, - // title: "MDN Web Docs", - // imgurl: "https://avatars.githubusercontent.com/u/7565578?v=4&s=640", - // desc: "The web's most comprehensive resource for web developers", - // siteurl: "https://developer.mozilla.org", - // tags: ["Docs", "Reference"], - // }, -]; - -// 获取所有友情链接数据 -export function getFriendsList(): FriendItem[] { - return friendsData; -} - -// 获取随机排序的友情链接数据 -export function getShuffledFriendsList(): FriendItem[] { - const shuffled = [...friendsData]; - for (let i = shuffled.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; - } - return shuffled; -} diff --git a/src/data/projects.ts b/src/data/projects.ts deleted file mode 100644 index 89f4906..0000000 --- a/src/data/projects.ts +++ /dev/null @@ -1,82 +0,0 @@ -// 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(); - projectsData.forEach((project) => { - project.techStack.forEach((tech) => { - techSet.add(tech); - }); - }); - return Array.from(techSet).sort(); -}; diff --git a/src/data/skills.ts b/src/data/skills.ts deleted file mode 100644 index a4c0733..0000000 --- a/src/data/skills.ts +++ /dev/null @@ -1,310 +0,0 @@ -// 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, - }; -}; diff --git a/src/data/timeline.ts b/src/data/timeline.ts deleted file mode 100644 index 8defbf9..0000000 --- a/src/data/timeline.ts +++ /dev/null @@ -1,110 +0,0 @@ -// 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, - }; -}; diff --git a/src/styles/main.css b/src/styles/main.css index 7c00935..ba1234f 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -18,8 +18,8 @@ } @font-face { - font-family: '萝莉体 第二版'; - src: url('/assets/font/萝莉体 第二版.woff2') format('woff2'); + font-family: 'futomaru401'; + src: url('/assets/font/futomaru401.woff2') format('woff2'); font-weight: 400; font-display: swap; }