This commit is contained in:
2025-12-08 01:03:07 +08:00
commit 5c77d25b6d
334 changed files with 71475 additions and 0 deletions

48
.env.example Normal file
View File

@@ -0,0 +1,48 @@
# Mizuki 博客环境变量配置示例
# 复制此文件为 .env 并根据需要填写实际值
# ============================================
# 内容仓库配置 (代码内容分离)
# 项目地址:https://github.com/matsuzaka-yuki/Mizuki-Content
# ============================================
# 是否启用内容分离功能 (true/false)
# true: 启用内容分离,从独立仓库同步内容
# false: 禁用内容分离,使用本地内容 (默认模式)
# 注意: 如果不使用内容分离功能,可以注释掉或设置为 false
ENABLE_CONTENT_SYNC=false
# 内容仓库的 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://github.com/your-username/Mizuki-Content.git
# 内容目录路径 (相对于项目根目录)
# 默认: ./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

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.js linguist-language=astro

View File

@@ -0,0 +1,59 @@
name: Bug Report
description: Create a report to help us improve
title: "[Bug]: "
labels: ["bug"]
assignees:
- L4Ph
- saicaca
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: to-reproduce
attributes:
label: To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: dropdown
id: os
attributes:
label: OS
multiple: true
options:
- Windows
- macOS
- Linux
- Android
- iOS
- type: input
id: browser
attributes:
label: Browser
placeholder: e.g. chrome, safari
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context about the problem here.

View File

@@ -0,0 +1,41 @@
name: Feature Request
description: Suggest an idea for this project
title: "[Feature]: "
labels: ["enhancement"]
assignees:
- saicaca
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request!
- type: textarea
id: related-problem
attributes:
label: Is your feature request related to a problem?
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
- type: markdown
attributes:
value: |
**Disclaimer**
Please note that this feature request is at the discretion of the repository owner, @saicaca, and its implementation is not guaranteed.

View File

@@ -0,0 +1,11 @@
name: Custom Issue
description: Describe your issue here.
title: "[Other]: "
body:
- type: textarea
id: issue-description
attributes:
label: Issue Description
description: Please describe your issue.
validations:
required: true

22
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
groups:
patch-updates:
patterns:
- "*"
update-types:
- "patch"
minor-updates:
patterns:
- "*"
update-types:
- "minor"
pull-request-branch-name:
separator: "-"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

37
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,37 @@
## Type of change
- [ ] Bug fix (a non-breaking change that fixes an issue)
- [ ] New feature (a non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Other (please describe):
## Checklist
- [ ] I have read the [**CONTRIBUTING**](https://github.com/saicaca/fuwari/blob/main/CONTRIBUTING.md) document.
- [ ] I have checked to ensure that this Pull Request is not for personal changes.
- [ ] I have performed a self-review of my own code.
- [ ] My changes generate no new warnings.
## Related Issue
<!-- Please link to the issue that this pull request addresses. e.g. #123 -->
## Changes
<!-- Please describe the changes you made in this pull request. -->
## How To Test
<!-- Please describe how you tested your changes. -->
## Screenshots (if applicable)
<!-- If you made any UI changes, please include screenshots. -->
## Additional Notes
<!-- Any additional information that you want to share with the reviewer. -->

20
.github/workflows/biome.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Code quality
on:
push:
branches: [ main ] # Adjust branches as needed
pull_request:
branches: [ main ] # Adjust branches as needed
jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Biome
uses: biomejs/setup-biome@f382a98e582959e6aaac8e5f8b17b31749018780 # v2.5.0
with:
version: latest
- name: Run Biome
run: biome ci ./src --reporter=github

76
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: Build and Check
on:
push:
branches: [ main ] # Adjust branches as needed
pull_request:
branches: [ main ] # Adjust branches as needed
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check:
strategy:
matrix:
node: [ 22, 23 ]
runs-on: ubuntu-latest
name: Astro Check for Node.js ${{ matrix.node }}
steps:
- name: Setup Node.js
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: ${{ matrix.node }} # Use LTS
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
with:
run_install: false # Disable auto-install
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Astro Check
run: pnpm astro check
env:
# 测试构建时禁用内容同步,使用本地内容
ENABLE_CONTENT_SYNC: false
build:
strategy:
matrix:
node: [ 22, 23 ]
runs-on: ubuntu-latest
name: Astro Build for Node.js ${{ matrix.node }} # Corrected job name
steps:
- name: Setup Node.js
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: ${{ matrix.node }}
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
with:
run_install: false # Disable auto-install
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Astro Build
run: pnpm astro build
env:
ENABLE_CONTENT_SYNC: false

55
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: Deploy to Pages Branch
on:
# 每次推送到 `main` 分支时触发这个"工作流程"
# 如果你使用了别的分支名,请按需将 `main` 替换成你的分支名
push:
branches: [ main ]
# 允许你在 GitHub 上的 Actions 标签中手动触发此"工作流程"
workflow_dispatch:
# 需要写入权限来推送到pages分支
permissions:
contents: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout your repository using git
uses: actions/checkout@v4
with:
submodules: true # 支持 Git Submodule 模式
token: ${{ secrets.GITHUB_TOKEN }} # 自动访问同账号下的私有仓库
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.14.4
run_install: false
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Build site
run: pnpm run build
env:
# 如果需要启用内容分离,取消以下注释并配置
# ENABLE_CONTENT_SYNC: true
# CONTENT_REPO_URL: ${{ secrets.CONTENT_REPO_URL }}
# USE_SUBMODULE: true
# 其他环境变量
UMAMI_API_KEY: ${{ secrets.UMAMI_API_KEY }}
- name: Deploy to pages branch
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: pages # 部署到pages分支
folder: dist # Astro默认构建输出目录
clean: true # 清理目标分支中的旧文件

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# content repository (independent mode)
/content/
*.backup
# Large zip files
*.zip
# macOS-specific files
.DS_Store
.vercel
package-lock.json
bun.lockb
yarn.lock
# ide
.idea
*.iml
cache/
fuwari/
src/data/myself.ts
src/pages/myself.astro

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
manage-package-manager-versions = true

3
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"recommendations": ["biomejs.biome", "astro-build.astro-vscode"]
}

21
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit"
},
"liveServer.settings.root": "/dist",
"frontMatter.dashboard.openOnStart": false
}

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

21
LICENSE.MIT Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 saicaca
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

298
README.ja.md Normal file
View File

@@ -0,0 +1,298 @@
# 🌸 Mizuki
![Node.js >= 20](https://img.shields.io/badge/node.js-%3E%3D20-brightgreen)
![pnpm >= 9](https://img.shields.io/badge/pnpm-%3E%3D9-blue)
![Astro](https://img.shields.io/badge/Astro-5.12.8-orange)
![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-blue)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Mizuki Preview](../README.webp)
<table>
<tr>
<td><img alt="" src="docs/image/1.webp"></td>
<td><img alt="" src="docs/image/2.webp"></td>
<td><img alt="" src="docs/image/3.webp"></td>
<tr>
<tr>
<td><img alt="" src="docs/image/4.webp"></td>
<td><img alt="" src="docs/image/5.webp"></td>
<td><img alt="" src="docs/image/6.webp"></td>
<tr>
</table>
[Astro](https://astro.build)をベースにした、先進的な機能と美しいデザインを備えた現代的な静的ブログテンプレートです。
[**🖥️ ライブデモ**](https://mizuki.mysqil.com/)
[**📝 ドキュメント**](https://docs.mizuki.mysqil.com/)
🌏 README 言語
[**English**](../README.md) /
[**中文**](../README.zh.md) /
[**日本語**](./README.ja.md) /
[**中文繁体**](./README.tw.md) /
![設定](../configuration.svg)
### 🔧 コンポーネント設定システムの再構築
- **統一された設定アーキテクチャ:** 動的コンポーネント管理と順序設定をサポートする全く新しいモジュラーコンポーネント設定システム
- **設定駆動のコンポーネントローディング:** SideBarコンポーネントを再構築し、完全に設定ベースのコンポーネントローディングメカニズムを実装
- **統一制御スイッチ:** 音楽プレーヤーとお知らせコンポーネントの独立したenableスイッチを削除し、sidebarLayoutConfigによる統一制御に
- **レスポンシブレイアウト適応:** コンポーネントがレスポンシブレイアウトをサポートし、デバイスタイプに基づいて表示を自動調整
### 📐 レイアウトシステムの最適化
### 🎛️ 設定ファイル形式の標準化
- **Umami API キー(任意):** Umami アナリティクスを使用する場合は、デプロイ先プラットフォームに環境変数 `UMAMI_API_KEY` を設定するか、プロジェクトの設定ファイルに直接キーを記載することを推奨します。
- **型安全性:** 設定の型安全性を確保する包括的なTypeScript型定義
- **拡張性:** カスタムコンポーネントタイプと設定オプションのサポート
### 🧹 コード最適化
- **テストファイルのクリーンアップ:** 未使用のテスト設定と依存関係を削除し、プロジェクトサイズを削減
- **コード構造の最適化:** コンポーネントアーキテクチャを改善し、コードの保守性を向上
- **パフォーマンス向上:** コンポーネントローディングロジックを最適化し、ページレンダリングパフォーマンスを向上
---
## ✨ 機能
### 🎨 デザインとインターフェース
- [x] [Astro](https://astro.build)と[Tailwind CSS](https://tailwindcss.com)で構築
- [x] [Swup](https://swup.js.org/)を使用したスムーズなアニメーションとページ遷移
- [x] システム設定検出機能付きのライト/ダークテーマ切り替え
- [x] カスタマイズ可能なテーマカラーと動的バナーカルーセル
- [x] カルーセル、透明度、ぼかし効果を備えた全画面背景画像
- [x] すべてのデバイスに対応した完全レスポンシブデザイン
- [x] JetBrains Monoフォントによる美しいタイポグラフィ
### 🔍 コンテンツと検索
- [x] [Pagefind](https://pagefind.app/)ベースの高度な検索機能
- [x] 構文強調表示付きの[拡張Markdown機能](#-markdown拡張機能)
- [x] 自動スクロール機能付きのインタラクティブな目次
- [x] RSSフィード生成
- [x] 読書時間の推定
- [x] 記事のカテゴリ化とタグシステム
### 📱 特別ページ
- [x] **アニメトラッキングページ** - アニメの視聴進捗と評価を追跡
- [x] **友達ページ** - 友達のウェブサイトを美しいカードで紹介
- [x] **日記ページ** - ソーシャルメディアのような生活の瞬間を共有
- [x] **アーカイブページ** - 記事の整理されたタイムラインビュー
- [x] **アバウトページ** - カスタマイズ可能な自己紹介
### 🛠 技術的特徴
- [x] [Expressive Code](https://expressive-code.com/)ベースの**拡張コードブロック**
- [x] KaTeXレンダリングによる**数式サポート**
- [x] PhotoSwipeギャラリー統合による**画像最適化**
- [x] サイトマップとメタタグを含む**SEO最適化**
- [x] 遅延読み込みとキャッシュによる**パフォーマンス最適化**
- [x] Twikoo統合による**コメントシステム**
## 🚀 クイックスタート
### 📦 インストール
1. **リポジトリをクローン:**
```bash
git clone https://github.com/matsuzaka-yuki/mizuki.git
cd mizuki
```
2. **依存関係をインストール:**
```bash
# pnpmがインストールされていない場合はインストール
npm install -g pnpm
# プロジェクトの依存関係をインストール
pnpm install
```
3. **ブログを設定:**
- `src/config.ts`を編集してブログ設定をカスタマイズ
- サイト情報、テーマカラー、バナー画像、ソーシャルリンクを更新
- 機能ページの機能を設定
4. **開発サーバーを起動:**
```bash
pnpm dev
```
ブログは`http://localhost:4321`で利用可能になります
### 📝 コンテンツ管理
- **新しい投稿を作成:** `pnpm new-post <ファイル名>`
- **投稿を編集:** `src/content/posts/`内のファイルを修正
- **特別ページをカスタマイズ:** `src/content/spec/`内のファイルを編集
- **画像を追加:** 画像を`src/assets/`または`public/`に配置
### 🚀 デプロイ
ブログを任意の静的ホスティングプラットフォームにデプロイ:
- **Vercel** GitHubリポジトリをVercelに接続
- **Netlify** GitHubから直接デプロイ
- **GitHub Pages** 付属のGitHub Actionsワークフローを使用
- **Cloudflare Pages** リポジトリを接続
デプロイ前に、`astro.config.mjs`の`site` URLを更新してください。
## 📝 投稿フロントマター形式
```yaml
---
title: 私の最初のブログ投稿
published: 2023-09-09
description: これは私の新しいブログの最初の投稿です。
image: ./cover.jpg
tags: [タグ1, タグ2]
category: フロントエンド
draft: false
pinned: false
lang: ja # 記事の言語がconfig.tsのサイト言語と異なる場合のみ設定
---
```
### フロントマターフィールドの説明
- **title**: 記事のタイトル(必須)
- **published**: 公開日(必須)
- **description**: SEOとプレビュー用の記事の説明
- **image**: カバー画像のパス(記事ファイルからの相対パス)
- **tags**: カテゴリ化のためのタグの配列
- **category**: 記事のカテゴリ
- **draft**: 本番環境で記事を非表示にするには`true`に設定
- **pinned**: 記事を上部に固定するには`true`に設定
- **lang**: 記事の言語(サイトのデフォルト言語と異なる場合のみ設定)
### ピン留め記事機能
`pinned`フィールドを使用すると、重要な記事をブログリストの上部に固定できます。ピン留めされた記事は、公開日に関係なく、常に通常の記事の前に表示されます。
**使用方法:**
```yaml
pinned: true # この記事を上部に固定
pinned: false # 通常の記事(デフォルト)
```
**ソートルール:**
1. ピン留め記事が最初に表示され、公開日でソート(最新が先)
2. 通常の記事がその後に表示され、公開日でソート(最新が先)
## 🧩 Markdown拡張機能
Mizukiは標準のGitHub Flavored Markdownを超える拡張機能をサポートしています
### 📝 拡張ライティング
- **コールアウト:** `> [!NOTE]`、`> [!TIP]`、`> [!WARNING]`などを使用して美しい注釈ボックスを作成
- **数式:** `$インライン$`と`$$ブロック$$`構文を使用してLaTeX数式を記述
- **コード強調表示:** 行番号とコピーボタン付きの高度な構文強調表示
- **GitHubカード** `::github{repo="ユーザー/リポジトリ"}`を使用してリポジトリカードを埋め込み
### 🎨 ビジュアル要素
- **画像ギャラリー:** 画像表示のための自動PhotoSwipe統合
- **折りたたみセクション:** 展開可能なコンテンツブロックを作成
- **カスタムコンポーネント:** 特別なディレクティブでコンテンツを強化
### 📊 コンテンツ整理
- **目次:** 見出しから自動生成され、スムーズスクロールをサポート
- **読書時間:** 自動計算して表示
- **記事メタデータ:** カテゴリとタグを含む豊富なフロントマターサポート
## ⚡ コマンド
すべてのコマンドはプロジェクトルートから実行します:
| コマンド | アクション |
|:---------------------------|:----------------------------------------|
| `pnpm install` | 依存関係をインストール |
| `pnpm dev` | `localhost:4321`でローカル開発サーバーを起動 |
| `pnpm build` | 本番サイトを`./dist/`にビルド |
| `pnpm preview` | デプロイ前にビルドをローカルでプレビュー |
| `pnpm check` | Astroエラーチェックを実行 |
| `pnpm format` | Biomeでコードをフォーマット |
| `pnpm lint` | コードの問題をチェックして修正 |
| `pnpm new-post <ファイル名>` | 新しいブログ投稿を作成 |
| `pnpm astro ...` | Astro CLIコマンドを実行 |
## 🎯 設定ガイド
### 🔧 基本設定
`src/config.ts`を編集してブログをカスタマイズ:
```typescript
export const siteConfig: SiteConfig = {
title: "あなたのブログ名",
subtitle: "あなたのブログの説明",
lang: "ja", // または "zh-CN"、"en" など
themeColor: {
hue: 210, // 0-360、テーマの色相
fixed: false, // テーマカラーピッカーを非表示
},
banner: {
enable: true,
src: ["assets/banner/1.webp"], // バナー画像
carousel: {
enable: true,
interval: 0.8, // 秒
},
},
};
```
### 📱 機能ページの設定
- **アニメページ:** `src/pages/anime.astro`でアニメリストを編集
- **友達ページ:** `src/content/spec/friends.md`で友達データを編集
- **日記ページ:** `src/pages/diary.astro`で瞬間を編集
- **アバウトページ:** `src/content/spec/about.md`でコンテンツを編集
## ✏️ 貢献
貢献は歓迎します!お気軽に問題やプルリクエストを提出してください。
1. リポジトリをフォーク
2. 機能ブランチを作成 (`git checkout -b feature/amazing-feature`)
3. 変更をコミット (`git commit -m 'Add some amazing feature'`)
4. ブランチにプッシュ (`git push origin feature/amazing-feature`)
5. プルリクエストを開く
## 📄 ライセンス
このプロジェクトはApacheライセンス2.0の下でライセンスされています - 詳細は[LICENSE](../LICENSE)ファイルをご覧ください。
### 元のプロジェクトライセンス
このプロジェクトは[Fuwari](https://github.com/saicaca/fuwari)に基づいて開発され、元のプロジェクトはMITライセンスを使用しています。MITライセンスの要件に従い、元の著作権表示と許可通知はLICENSE.MITファイルに含まれています。
## 🙏 謝辞
- オリジナルの[Fuwari](https://github.com/saicaca/fuwari)テンプレートをベースにしています
- [Yukina](https://github.com/WhitePaper233/yukina) - 美しくエレガントなブログテンプレートにインスパイアされました
- 一部のデザインは[Firefly](https://github.com/CuteLeaf/Firefly)テンプレートからインスピレーションを得ています
- [Pio](https://github.com/Dreamer-Paul/Pio)を使用してかわいいLive2D看板娘プラグインを実装
- [Astro](https://astro.build)と[Tailwind CSS](https://tailwindcss.com)で構築
- アイコンは[Iconify](https://iconify.design/)から
### 🌸 特別な感謝
- **[Fuwari](https://github.com/saicaca/fuwari)** by saicaca - このプロジェクトのベースとなるオリジナルテンプレート。このような美しく機能的なテンプレートを作成していただきありがとうございます。
- **[Yukina](https://github.com/WhitePaper233/yukina)** - このプロジェクトの形成に役立ったデザインのインスピレーションと創造性を提供してくれたことに感謝します。Yukinaは優れたデザイン原則とユーザーエクスペリエンスを示す、エレガントなブログテンプレートです。
- **[Firefly](https://github.com/CuteLeaf/Firefly)** - 優れたレイアウトデザインのアイデアを提供していただきありがとうございます。デュアルサイドバーレイアウト、記事の2カラムグリッドレイアウト、およびいくつかのウィジェットのデザインと実装により、Mizukiのインターフェースがより豊かになりました。
## 🍀 コントリビューター
このプロジェクトに貢献してくださったすべてのコントリビューターに感謝します。質問や提案がある場合は、[Issue](https://github.com/matsuzaka-yuki/Mizuki/issues)または[Pull Request](https://github.com/matsuzaka-yuki/Mizuki/pulls)を提出してください。
<a href="https://github.com/matsuzaka-yuki/Mizuki/graphs/contributors">
<img src="https://contrib.rocks/image?repo=matsuzaka-yuki/Mizuki" />
</a>
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=matsuzaka-yuki/Mizuki&type=Date)](https://star-history.com/#matsuzaka-yuki/Mizuki&Date)
---
⭐ このプロジェクトが役立つと思ったら、スターを付けることを検討してください!

312
README.md Normal file
View File

@@ -0,0 +1,312 @@
# 🌸 Mizuki
![Node.js >= 20](https://img.shields.io/badge/node.js-%3E%3D20-brightgreen)
![pnpm >= 9](https://img.shields.io/badge/pnpm-%3E%3D9-blue)
![Astro](https://img.shields.io/badge/Astro-5.15.3-orange)
![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-blue)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Mizuki Preview](./README.webp)
<table>
<tr>
<td><img alt="" src="docs/image/1.webp"></td>
<td><img alt="" src="docs/image/2.webp"></td>
<td><img alt="" src="docs/image/3.webp"></td>
<tr>
<tr>
<td><img alt="" src="docs/image/4.webp"></td>
<td><img alt="" src="docs/image/5.webp"></td>
<td><img alt="" src="docs/image/6.webp"></td>
<tr>
</table>
A modern, feature-rich static blog template built with [Astro](https://astro.build), featuring advanced functionality and beautiful design.
[**🖥️ Live Demo**](https://mizuki.mysqil.com/)
[**📝 Documentation**](https://docs.mizuki.mysqil.com/)
🌏 README Languages
[**English**](./README.md) /
[**中文**](./README.zh.md) /
[**日本語**](./docs/README.ja.md) /
[**中文繁体**](./docs/README.tw.md) /
![Configuration](configuration.svg)
### 🔧 Component Configuration System Restructuring
- **Unified Configuration Architecture:** Brand new modular component configuration system, supporting dynamic component management and order configuration
- **Configuration-Driven Component Loading:** Restructured SideBar component, implementing fully configuration-based component loading mechanism
- **Unified Control Switches:** Removed independent enable switches for music player and announcement components, unified control through sidebarLayoutConfig
- **Responsive Layout Adaptation:** Components support responsive layouts, automatically adjusting display based on device type
### 📐 Layout System Optimization
- **Dynamic Sidebar Position Adjustment:** Support for left/right sidebar switching, with automatic layout adaptation
- **Intelligent Article Directory Positioning:** When sidebar is on the right, article navigation automatically moves to the left, providing a better reading experience
- **Grid Layout Improvements:** Optimized CSS Grid layout, resolving container width anomaly issues
### 🎛️ Configuration File Format Standardization
- **Standardized Configuration Format:** Created unified component configuration file format specifications
- **Type Safety:** Comprehensive TypeScript type definitions ensuring configuration type safety
- **Extensibility:** Support for custom component types and configuration options
### 🧹 Code Optimization
- **Test File Cleanup:** Removed unused test configurations and dependencies, reducing project size
- **Code Structure Optimization:** Improved component architecture, enhancing code maintainability
- **Performance Improvement:** Optimized component loading logic, improving page rendering performance
---
## ✨ Features
### 🎨 Design & Interface
- [x] Built with [Astro](https://astro.build) and [Tailwind CSS](https://tailwindcss.com)
- [x] Smooth animations and page transitions using [Swup](https://swup.js.org/)
- [x] Light/dark theme switching with system preference detection
- [x] Customizable theme colors and dynamic banner carousel
- [x] Fullscreen background images with carousel, opacity, and blur effects
- [x] Fully responsive design for all devices
- [x] Beautiful typography with JetBrains Mono font
### 🔍 Content & Search
- [x] Advanced search functionality based on [Pagefind](https://pagefind.app/)
- [x] [Enhanced Markdown features](#-markdown-extensions) with syntax highlighting
- [x] Interactive table of contents with auto-scrolling
- [x] RSS feed generation
- [x] Reading time estimation
- [x] Article categorization and tagging system
### 📱 Special Pages
- [x] **Anime Tracking Page** - Track anime watching progress and ratings
- [x] **Friends Page** - Beautiful cards showcasing friend websites
- [x] **Diary Page** - Share life moments, similar to social media
- [x] **Archive Page** - Organized timeline view of articles
- [x] **About Page** - Customizable personal introduction
### 🛠 Technical Features
- [x] **Enhanced code blocks** based on [Expressive Code](https://expressive-code.com/)
- [x] **Math formula support** with KaTeX rendering
- [x] **Image optimization** with PhotoSwipe gallery integration
- [x] **SEO optimization** including sitemaps and meta tags
- [x] **Performance optimization** with lazy loading and caching
- [x] **Comment system** with Twikoo integration
## 🚀 Quick Start
### 📦 Installation
1. **Clone the repository:**
```bash
git clone https://github.com/matsuzaka-yuki/mizuki.git
cd mizuki
```
2. **Install dependencies:**
```bash
# Install pnpm if not already installed
npm install -g pnpm
# Install project dependencies
pnpm install
```
3. **Configure your blog:**
- Edit `src/config.ts` to customize blog settings
- Update site information, theme colors, banner images, and social links
- Configure feature page functionality
4. **Start the development server:**
```bash
pnpm dev
```
Your blog will be available at `http://localhost:4321`
### 📝 Content Management
- **Create new posts:** `pnpm new-post <filename>`
- **Edit posts:** Modify files in `src/content/posts/`
- **Customize special pages:** Edit files in `src/content/spec/`
- **Add images:** Place images in `src/assets/` or `public/`
### 🚀 Deployment
Deploy your blog to any static hosting platform:
- **Vercel:** Connect your GitHub repository to Vercel
- **Netlify:** Deploy directly from GitHub
- **GitHub Pages:** Use the included GitHub Actions workflow
- **Cloudflare Pages:** Connect your repository
- **Environment Variable Configuration (Optional):** Configure in `.env` file or deployment platform
```bash
# Umami API key for accessing Umami analytics data
# If Umami is enabled in config.ts, it's recommended to configure the API key here
UMAMI_API_KEY=your_umami_api_key_here
# bcrypt salt rounds (10-14 recommended, default 12)
BCRYPT_SALT_ROUNDS=12
```
Before deployment, update the `siteURL` in `src/config.ts`.
**Not recommended** to commit the `.env` file to Git. The `.env` file should only be used for local debugging or building. For cloud platform deployment, it's recommended to configure via the platform's `environment variables` settings.
## 📝 Post Frontmatter Format
```yaml
---
title: My First Blog Post
published: 2023-09-09
description: This is the first post of my new blog.
image: ./cover.jpg
tags: [tag1, tag2]
category: Frontend
draft: false
pinned: false
lang: en # Only set when article language differs from site language in config.ts
---
```
### Frontmatter Field Descriptions
- **title**: Article title (required)
- **published**: Publication date (required)
- **description**: Article description for SEO and previews
- **image**: Cover image path (relative to article file)
- **tags**: Array of tags for categorization
- **category**: Article category
- **draft**: Set to `true` to hide article in production
- **pinned**: Set to `true` to pin article to top
- **lang**: Article language (only set when different from site default)
### Pinned Articles Feature
The `pinned` field allows you to pin important articles to the top of your blog list. Pinned articles will always appear before regular articles regardless of their publication date.
**Usage:**
```yaml
pinned: true # Pin this article to the top
pinned: false # Regular article (default)
```
**Sorting Rules:**
1. Pinned articles appear first, sorted by publication date (newest first)
2. Regular articles follow, sorted by publication date (newest first)
## 🧩 Markdown Extensions
Mizuki supports enhanced features beyond standard GitHub Flavored Markdown:
### 📝 Enhanced Writing
- **Callouts:** Create beautiful annotation boxes using `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, etc.
- **Math Formulas:** Write LaTeX math formulas using `$inline$` and `$$block$$` syntax
- **Code Highlighting:** Advanced syntax highlighting with line numbers and copy buttons
- **GitHub Cards:** Embed repository cards using `::github{repo="user/repo"}`
### 🎨 Visual Elements
- **Image Gallery:** Automatic PhotoSwipe integration for image viewing
- **Collapsible Sections:** Create expandable content blocks
- **Custom Components:** Enhance content with special directives
### 📊 Content Organization
- **Table of Contents:** Automatically generated from headings with smooth scrolling
- **Reading Time:** Automatically calculated and displayed
- **Article Metadata:** Rich frontmatter support with categories and tags
## ⚡ Commands
All commands are run from the project root:
| Command | Action |
|:---------------------------|:-----------------------------------------|
| `pnpm install` | Install dependencies |
| `pnpm dev` | Start local dev server at `localhost:4321` |
| `pnpm build` | Build production site to `./dist/` |
| `pnpm preview` | Preview build locally before deployment |
| `pnpm check` | Run Astro error checking |
| `pnpm format` | Format code with Biome |
| `pnpm lint` | Check and fix code issues |
| `pnpm new-post <filename>` | Create a new blog post |
| `pnpm astro ...` | Run Astro CLI commands |
## 🎯 Configuration Guide
### 🔧 Basic Configuration
Edit `src/config.ts` to customize your blog:
```typescript
export const siteConfig: SiteConfig = {
title: "Your Blog Name",
subtitle: "Your Blog Description",
lang: "en", // or "zh-CN", "ja", etc.
themeColor: {
hue: 210, // 0-360, theme hue
fixed: false, // Hide theme color picker
},
banner: {
enable: true,
src: ["assets/banner/1.webp"], // Banner images
carousel: {
enable: true,
interval: 0.8, // seconds
},
},
};
```
### 📱 Feature Page Configuration
- **Anime Page:** Edit anime list in `src/pages/anime.astro`
- **Friends Page:** Edit friend data in `src/content/spec/friends.md`
- **Diary Page:** Edit moments in `src/pages/diary.astro`
- **About Page:** Edit content in `src/content/spec/about.md`
## ✏️ Contributing
Contributions are welcome! Feel free to submit issues and pull requests.
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## 📄 License
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
### Original Project License
This project is based on [Fuwari](https://github.com/saicaca/fuwari), which is licensed under the MIT License. The original copyright notice and permission notice are included in the LICENSE.MIT file in accordance with the MIT License requirements.
## 🙏 Acknowledgements
- Based on the original [Fuwari](https://github.com/saicaca/fuwari) template
- Inspired by [Yukina](https://github.com/WhitePaper233/yukina) - a beautiful and elegant blog template
- Some designs are inspired by [Firefly](https://github.com/CuteLeaf/Firefly) template
- Uses [Pio](https://github.com/Dreamer-Paul/Pio) to implement the adorable Live2D mascot plugin
- Built with [Astro](https://astro.build) and [Tailwind CSS](https://tailwindcss.com)
- Icons from [Iconify](https://iconify.design/)
### 🌸 Special Thanks
- **[Fuwari](https://github.com/saicaca/fuwari)** by saicaca - The original template that this project is based on. Thank you for creating such a beautiful and functional template.
- **[Yukina](https://github.com/WhitePaper233/yukina)** - Thanks for providing design inspiration and creativity that helped shape this project. Yukina is an elegant blog template that demonstrates excellent design principles and user experience.
- **[Firefly](https://github.com/CuteLeaf/Firefly)** - Thanks for providing excellent layout design ideas. The dual sidebar layout, article dual-column grid layout, and some widget designs and implementations have enriched Mizuki's interface.
## 🍀 Contributors
Thanks to all contributors for their contributions to this project. If you have any questions or suggestions, please submit an [Issue](https://github.com/matsuzaka-yuki/Mizuki/issues) or [Pull Request](https://github.com/matsuzaka-yuki/Mizuki/pulls).
<a href="https://github.com/matsuzaka-yuki/Mizuki/graphs/contributors">
<img src="https://contrib.rocks/image?repo=matsuzaka-yuki/Mizuki" />
</a>
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=matsuzaka-yuki/Mizuki&type=Date)](https://star-history.com/#matsuzaka-yuki/Mizuki&Date)
---
⭐ If you find this project helpful, please consider giving it a star!

303
README.tw.md Normal file
View File

@@ -0,0 +1,303 @@
# 🌸 Mizuki
![Node.js >= 20](https://img.shields.io/badge/node.js-%3E%3D20-brightgreen)
![pnpm >= 9](https://img.shields.io/badge/pnpm-%3E%3D9-blue)
![Astro](https://img.shields.io/badge/Astro-5.12.8-orange)
![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-blue)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Mizuki Preview](../README.webp)
<table>
<tr>
<td><img alt="" src="image/1.webp"></td>
<td><img alt="" src="image/2.webp"></td>
<td><img alt="" src="image/3.webp"></td>
<tr>
<tr>
<td><img alt="" src="image/4.webp"></td>
<td><img alt="" src="image/5.webp"></td>
<td><img alt="" src="image/6.webp"></td>
<tr>
</table>
一個現代化、功能豐富的靜態部落格模板,基於 [Astro](https://astro.build) 構建,具有先進的功能和精美的設計。
[**🖥️ 線上演示**](https://mizuki.mysqil.com/)
[**📝 使用者文檔**](https://docs.mizuki.mysqil.com/)
🌏 README 語言
[**English**](../README.md) /
[**中文**](../README.zh.md) /
[**日本語**](./README.ja.md) /
[**中文繁体**](./README.tw.md) /
![Configuration](../configuration.svg)
### 🔧 元件配置系統重構
- **統一配置架構:** 全新的模組化元件配置體系,支援動態元件管理和順序配置
- **配置驅動的元件載入:** 重構 SideBar 元件,實現完全基於配置的元件載入機制
- **統一控制開關:** 移除音樂播放器和公告元件的獨立 enable 開關,統一由 sidebarLayoutConfig 控制
- **響應式佈局適配:** 元件支援響應式佈局,可根據裝置類型自動調整顯示
### 📐 佈局系統優化
- **側邊欄位置動態調整:** 支援左右側邊欄切換,佈局自動適配
- **文章目錄智能定位:** 當側邊欄在右側時,文章導航自動移至左側,提供更好的閱讀體驗
- **網格佈局改進:** 優化 CSS Grid 佈局,解決容器寬度異常問題
### 🎛️ 配置文件格式規範
- **標準化配置格式:** 創建統一的元件配置文件格式規範
- **類型安全:** 完善的 TypeScript 類型定義,確保配置的類型安全
- **可擴展性:** 支援自定義元件類型和配置選項
### 🧹 程式碼優化
- **測試文件清理:** 移除未使用的測試配置和依賴,減少專案體積
- **程式碼結構優化:** 改進元件架構,提升程式碼可維護性
- **效能提升:** 優化元件載入邏輯,提升頁面渲染效能
---
## ✨ 功能特性
### 🎨 設計與界面
- [x] 基於 [Astro](https://astro.build) 和 [Tailwind CSS](https://tailwindcss.com) 構建
- [x] 使用 [Swup](https://swup.js.org/) 實現流暢的動畫和頁面過渡
- [x] 明暗主題切換,支援系統偏好檢測
- [x] 可自定義主題色彩和動態橫幅輪播
- [x] 全屏背景圖片,支援輪播、透明度和模糊效果
- [x] 全裝置響應式設計
- [x] 使用 JetBrains Mono 字體的優美排版
### 🔍 內容與搜尋
- [x] 基於 [Pagefind](https://pagefind.app/) 的高級搜尋功能
- [x] [增強的 Markdown 功能](#-markdown-擴展語法),支援語法高亮
- [x] 互動式目錄,支援自動滾動
- [x] RSS 訂閱生成
- [x] 閱讀時間估算
- [x] 文章分類和標籤系統
### 📱 特色頁面
- [x] **追番頁面** - 追蹤動畫觀看進度和評分
- [x] **友鏈頁面** - 精美卡片展示朋友網站
- [x] **日記頁面** - 分享生活瞬間,類似社交媒體
- [x] **歸檔頁面** - 有序的文章時間線視圖
- [x] **關於頁面** - 可自定義的個人介紹
### 🛠 技術特性
- [x] **增強程式碼區塊**,基於 [Expressive Code](https://expressive-code.com/)
- [x] **數學公式支援**KaTeX 渲染
- [x] **圖片優化**PhotoSwipe 畫廊整合
- [x] **SEO 優化**,包含網站地圖和元標籤
- [x] **效能優化**,懶加載和快取機制
- [x] **評論系統**,支援 Twikoo 整合
## 🚀 快速開始
### 📦 安裝
1. **克隆儲存庫:**
```bash
git clone https://github.com/matsuzaka-yuki/mizuki.git
cd mizuki
```
2. **安裝依賴:**
```bash
# 如果沒有安裝 pnpm先安裝
npm install -g pnpm
# 安裝專案依賴
pnpm install
```
3. **配置部落格:**
- 編輯 `src/config.ts` 自定義部落格設置
- 更新網站資訊、主題色彩、橫幅圖片和社交連結
- 配置翻譯設置和特色頁面功能
4. **啟動開發伺服器:**
```bash
pnpm dev
```
部落格將在 `http://localhost:4321` 可用
### 📝 內容管理
- **創建新文章:** `pnpm new-post <檔案名>`
- **編輯文章:** 修改 `src/content/posts/` 中的檔案
- **自定義頁面:** 編輯 `src/content/spec/` 中的特殊頁面
- **添加圖片:** 將圖片放在 `src/assets/` 或 `public/` 中
### 🚀 部署
將部落格部署到任何靜態託管平台:
- **Vercel** 連接 GitHub 儲存庫到 Vercel
- **Netlify** 直接從 GitHub 部署
- **GitHub Pages** 使用包含的 GitHub Actions 工作流
- **Cloudflare Pages** 連接您的儲存庫
部署前,請在 `astro.config.mjs` 中更新 `site` URL。
- **環境變數配置:** 如果你需要使用 Umami 統計,建議在部署平台設定環境變數 `UMAMI_API_KEY` 為你的 Umami API 金鑰,或直接在配置檔中修改。
## 📝 文章前言格式
```yaml
---
title: 我的第一篇部落格文章
published: 2023-09-09
description: 這是我新部落格的第一篇文章。
image: ./cover.jpg
tags: [標籤1, 標籤2]
category: 前端
draft: false
pinned: false
lang: zh-TW # 僅當文章語言與 config.ts 中的網站語言不同時設置
---
```
### Frontmatter 欄位說明
- **title**: 文章標題(必需)
- **published**: 發布日期(必需)
- **description**: 文章描述,用於 SEO 和預覽
- **image**: 封面圖片路徑(相對於文章檔案)
- **tags**: 標籤陣列,用於分類
- **category**: 文章分類
- **draft**: 設置為 `true` 在生產環境中隱藏文章
- **pinned**: 設置為 `true` 將文章置頂
- **lang**: 文章語言(僅當與網站預設語言不同時設置)
### 置頂文章功能
`pinned` 欄位允許您將重要文章置頂到部落格列表的頂部。置頂文章將始終顯示在普通文章之前,無論其發布日期如何。
**使用方法:**
```yaml
pinned: true # 將此文章置頂
pinned: false # 普通文章(預設)
```
**排序規則:**
1. 置頂文章優先顯示,按發布日期排序(最新在前)
2. 普通文章隨後顯示,按發布日期排序(最新在前)
## 🧩 Markdown 擴展語法
Mizuki 支援超越標準 GitHub Flavored Markdown 的增強功能:
### 📝 增強寫作
- **提示框:** 使用 `> [!NOTE]`、`> [!TIP]`、`> [!WARNING]` 等創建精美的標註框
- **數學公式:** 使用 `$行內$` 和 `$$塊級$$` 語法編寫 LaTeX 數學公式
- **程式碼高亮:** 高級語法高亮,支援行號和複製按鈕
- **GitHub 卡片:** 使用 `::github{repo="使用者/儲存庫"}` 嵌入儲存庫卡片
### 🎨 視覺元素
- **圖片畫廊:** 自動 PhotoSwipe 整合,支援圖片查看
- **可折疊部分:** 創建可展開的內容區塊
- **自定義元件:** 使用特殊指令增強內容
### 📊 內容組織
- **目錄:** 從標題自動生成,支援平滑滾動
- **閱讀時間:** 自動計算和顯示
- **文章元數據:** 豐富的前言支援,包含分類和標籤
## ⚡ 命令
所有命令都在專案根目錄運行:
| 命令 | 操作 |
|:---------------------------|:---------------------------------------|
| `pnpm install` | 安裝依賴 |
| `pnpm dev` | 在 `localhost:4321` 啟動本地開發伺服器 |
| `pnpm build` | 構建生產網站到 `./dist/` |
| `pnpm preview` | 在部署前本地預覽構建 |
| `pnpm check` | 運行 Astro 錯誤檢查 |
| `pnpm format` | 使用 Biome 格式化程式碼 |
| `pnpm lint` | 檢查並修復程式碼問題 |
| `pnpm new-post <檔案名>` | 創建新部落格文章 |
| `pnpm astro ...` | 運行 Astro CLI 命令 |
## 🎯 配置指南
### 🔧 基礎配置
編輯 `src/config.ts` 自定義您的部落格:
```typescript
export const siteConfig: SiteConfig = {
title: "您的部落格名稱",
subtitle: "您的部落格描述",
lang: "zh-TW", // 或 "zh-CN"、"en"、"ja" 等
themeColor: {
hue: 210, // 0-360主題色調
fixed: false, // 隱藏主題色選擇器
},
banner: {
enable: true,
src: ["assets/banner/1.webp"], // 橫幅圖片
carousel: {
enable: true,
interval: 0.8, // 秒
},
},
};
```
### 📱 特色頁面配置
- **追番頁面:** 在 `src/pages/anime.astro` 中編輯動畫列表
- **友鏈頁面:** 在 `src/content/spec/friends.md` 中編輯朋友數據
- **日記頁面:** 在 `src/pages/diary.astro` 中編輯動態
- **關於頁面:** 在 `src/content/spec/about.md` 中編輯內容
## ✏️ 貢獻
我們歡迎貢獻!請隨時提交問題和拉取請求。
1. Fork 儲存庫
2. 創建功能分支 (`git checkout -b feature/amazing-feature`)
3. 提交更改 (`git commit -m 'Add some amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 打開拉取請求
## 📄 許可證
本專案基於 Apache 許可證 2.0 - 查看 [LICENSE](../LICENSE) 檔案了解詳情。
### 原始專案許可證
本專案基於 [Fuwari](https://github.com/saicaca/fuwari) 開發,該專案使用 MIT 許可證。根據 MIT 許可證要求,原始版權聲明和許可聲明已包含在 LICENSE.MIT 檔案中。
## 🙏 致謝
- 基於原始 [Fuwari](https://github.com/saicaca/fuwari) 模板
- 靈感來源於 [Yukina](https://github.com/WhitePaper233/yukina) - 一個美麗優雅的部落格模板
- 部分設計來源於 [Firefly](https://github.com/CuteLeaf/Firefly) 模板
- 使用 [Pio](https://github.com/Dreamer-Paul/Pio) 實現可愛的 Live2D 看板娘外掛程式
- 使用 [Astro](https://astro.build) 和 [Tailwind CSS](https://tailwindcss.com) 構建
- 圖標來自 [Iconify](https://iconify.design/)
### 🌸 特別感謝
- **[Fuwari](https://github.com/saicaca/fuwari)** by saicaca - 本專案所基於的原始模板。感謝您創建了如此漂亮且功能強大的模板。
- **[Yukina](https://github.com/WhitePaper233/yukina)** - 感謝提供設計靈感和創意幫助塑造了這個專案。Yukina 是一個優雅的部落格模板,展現了出色的設計原則和使用者體驗。
- **[Firefly](https://github.com/CuteLeaf/Firefly)** - 感謝提供優秀的佈局設計思路,雙側邊欄佈局、文章雙列網格等佈局,及部分小元件的設計與實現,讓 Mizuki 的界面更加豐富。
## 🍀 貢獻者
感謝以下貢獻者對本專案做出的貢獻,如有問題或建議,請提交 [Issue](https://github.com/matsuzaka-yuki/Mizuki/issues) 或 [Pull Request](https://github.com/matsuzaka-yuki/Mizuki/pulls)。
<a href="https://github.com/matsuzaka-yuki/Mizuki/graphs/contributors">
<img src="https://contrib.rocks/image?repo=matsuzaka-yuki/Mizuki" />
</a>
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=matsuzaka-yuki/Mizuki&type=Date)](https://star-history.com/#matsuzaka-yuki/Mizuki&Date)
⭐ 如果您覺得這個專案有幫助,請考慮給它一個星標!

BIN
README.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

350
README.zh.md Normal file
View File

@@ -0,0 +1,350 @@
# 🌸 Mizuki
![Node.js >= 20](https://img.shields.io/badge/node.js-%3E%3D20-brightgreen)
![pnpm >= 9](https://img.shields.io/badge/pnpm-%3E%3D9-blue)
![Astro](https://img.shields.io/badge/Astro-5.15.3-orange)
![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-blue)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![Mizuki Preview](./README.webp)
<table>
<tr>
<td><img alt="" src="docs/image/1.webp"></td>
<td><img alt="" src="docs/image/2.webp"></td>
<td><img alt="" src="docs/image/3.webp"></td>
<tr>
<tr>
<td><img alt="" src="docs/image/4.webp"></td>
<td><img alt="" src="docs/image/5.webp"></td>
<td><img alt="" src="docs/image/6.webp"></td>
<tr>
</table>
一个现代化、功能丰富的静态博客模板,基于 [Astro](https://astro.build) 构建,具有先进的功能和精美的设计。
[**🖥️ 在线演示**](https://mizuki.mysqil.com/)
[**📝 用户文档**](https://docs.mizuki.mysqil.com/)
🌏 README 语言
[**English**](./README.md) /
[**中文**](./README.zh.md) /
[**日本語**](./docs/README.ja.md) /
[**中文繁体**](./docs/README.tw.md) /
![Configuration](configuration.svg)
### 🔧 组件配置系统重构
- **统一配置架构:** 全新的模块化组件配置体系,支持动态组件管理和顺序配置
- **配置驱动的组件加载:** 重构 SideBar 组件,实现完全基于配置的组件加载机制
- **统一控制开关:** 移除音乐播放器和公告组件的独立 enable 开关,统一由 sidebarLayoutConfig 控制
- **响应式布局适配:** 组件支持响应式布局,可根据设备类型自动调整显示
### 📐 布局系统优化
- **侧边栏位置动态调整:** 支持左右侧边栏切换,布局自动适配
- **文章目录智能定位:** 当侧边栏在右侧时,文章导航自动移至左侧,提供更好的阅读体验
- **网格布局改进:** 优化 CSS Grid 布局,解决容器宽度异常问题
### 🎛️ 配置文件格式规范
- **标准化配置格式:** 创建统一的组件配置文件格式规范
- **类型安全:** 完善的 TypeScript 类型定义,确保配置的类型安全
- **可扩展性:** 支持自定义组件类型和配置选项
### 🧹 代码优化
- **测试文件清理:** 移除未使用的测试配置和依赖,减少项目体积
- **代码结构优化:** 改进组件架构,提升代码可维护性
- **性能提升:** 优化组件加载逻辑,提升页面渲染性能
---
## ✨ 功能特性
### 🎨 设计与界面
- [x] 基于 [Astro](https://astro.build) 和 [Tailwind CSS](https://tailwindcss.com) 构建
- [x] 使用 [Swup](https://swup.js.org/) 实现流畅的动画和页面过渡
- [x] 明暗主题切换,支持系统偏好检测
- [x] 可自定义主题色彩和动态横幅轮播
- [x] 全屏背景图片,支持轮播、透明度和模糊效果
- [x] 全设备响应式设计
- [x] 使用 JetBrains Mono 字体的优美排版
### 🔍 内容与搜索
- [x] 基于 [Pagefind](https://pagefind.app/) 的高级搜索功能
- [x] [增强的 Markdown 功能](#-markdown-扩展语法),支持语法高亮
- [x] 交互式目录,支持自动滚动
- [x] RSS 订阅生成
- [x] 阅读时间估算
- [x] 文章分类和标签系统
### 📱 特色页面
- [x] **追番页面** - 追踪动画观看进度和评分
- [x] **友链页面** - 精美卡片展示朋友网站
- [x] **日记页面** - 分享生活瞬间,类似社交媒体
- [x] **归档页面** - 有序的文章时间线视图
- [x] **关于页面** - 可自定义的个人介绍
### 🛠 技术特性
- [x] **增强代码块**,基于 [Expressive Code](https://expressive-code.com/)
- [x] **数学公式支持**KaTeX 渲染
- [x] **图片优化**PhotoSwipe 画廊集成
- [x] **SEO 优化**,包含站点地图和元标签
- [x] **性能优化**,懒加载和缓存机制
- [x] **评论系统**,支持 Twikoo 集成
## 🚀 快速开始
### 📦 安装
1. **克隆仓库:**
```bash
git clone https://github.com/matsuzaka-yuki/mizuki.git
cd mizuki
```
2. **安装依赖:**
```bash
# 如果没有安装 pnpm先安装
npm install -g pnpm
# 安装项目依赖
pnpm install
```
3. **配置博客:**
- 编辑 `src/config.ts` 自定义博客设置
- 更新站点信息、主题色彩、横幅图片和社交链接
- 配置特色页面功能
- (可选) 配置内容仓库分离 - 见 [内容仓库配置](#-代码内容分离可选)
4. **启动开发服务器:**
```bash
pnpm dev
```
博客将在 `http://localhost:4321` 可用
### 📝 内容管理
- **创建新文章:** `pnpm new-post <文件名>`
- **编辑文章:** 修改 `src/content/posts/` 中的文件
- **自定义页面:** 编辑 `src/content/spec/` 中的特殊页面
- **添加图片:** 将图片放在 `src/assets/` 或 `public/` 中
### 🚀 部署
将博客部署到任何静态托管平台:
- **Vercel** 连接 GitHub 仓库到 Vercel
- **Netlify** 直接从 GitHub 部署
- **GitHub Pages** 使用包含的 GitHub Actions 工作流
- **Cloudflare Pages** 连接您的仓库
- **环境变量配置(可选):** 在 `.env` 文件或部署平台配置
```bash
# Umami API 密钥,用于访问 Umami 统计数据
# 如果在 config.ts 中启用了 Umami建议在此配置 API 密钥
UMAMI_API_KEY=your_umami_api_key_here
# bcrypt 盐值轮数10-14 推荐,默认 12
BCRYPT_SALT_ROUNDS=12
```
部署前,请在 `src/config.ts` 中更新 `siteURL`。
**不建议**将 `.env` 文件提交到 Git`.env` 应该仅在本地调试或构建使用。若要将项目在云平台部署,建议通过平台上的 `环境变量` 配置传入。
## 📝 文章前言格式
```yaml
---
title: 我的第一篇博客文章
published: 2023-09-09
description: 这是我新博客的第一篇文章。
image: ./cover.jpg
tags: [标签1, 标签2]
category: 前端
draft: false
pinned: false
lang: zh-CN # 仅当文章语言与 config.ts 中的站点语言不同时设置
---
```
### Frontmatter 字段说明
- **title**: 文章标题(必需)
- **published**: 发布日期(必需)
- **description**: 文章描述,用于 SEO 和预览
- **image**: 封面图片路径(相对于文章文件)
- **tags**: 标签数组,用于分类
- **category**: 文章分类
- **draft**: 设置为 `true` 在生产环境中隐藏文章
- **pinned**: 设置为 `true` 将文章置顶
- **lang**: 文章语言(仅当与站点默认语言不同时设置)
### 置顶文章功能
`pinned` 字段允许您将重要文章置顶到博客列表的顶部。置顶文章将始终显示在普通文章之前,无论其发布日期如何。
**使用方法:**
```yaml
pinned: true # 将此文章置顶
pinned: false # 普通文章(默认)
```
**排序规则:**
1. 置顶文章优先显示,按发布日期排序(最新在前)
2. 普通文章随后显示,按发布日期排序(最新在前)
## 🧩 Markdown 扩展语法
Mizuki 支持超越标准 GitHub Flavored Markdown 的增强功能:
### 📝 增强写作
- **提示框:** 使用 `> [!NOTE]`、`> [!TIP]`、`> [!WARNING]` 等创建精美的标注框
- **数学公式:** 使用 `$行内$` 和 `$$块级$$` 语法编写 LaTeX 数学公式
- **代码高亮:** 高级语法高亮,支持行号和复制按钮
- **GitHub 卡片:** 使用 `::github{repo="用户/仓库"}` 嵌入仓库卡片
### 🎨 视觉元素
- **图片画廊:** 自动 PhotoSwipe 集成,支持图片查看
- **可折叠部分:** 创建可展开的内容块
- **自定义组件:** 使用特殊指令增强内容
### 📊 内容组织
- **目录:** 从标题自动生成,支持平滑滚动
- **阅读时间:** 自动计算和显示
- **文章元数据:** 丰富的前言支持,包含分类和标签
## ⚡ 命令
所有命令都在项目根目录运行:
| 命令 | 操作 |
|:---------------------------|:---------------------------------------|
| `pnpm install` | 安装依赖 |
| `pnpm dev` | 在 `localhost:4321` 启动本地开发服务器 |
| `pnpm build` | 构建生产站点到 `./dist/` |
| `pnpm preview` | 在部署前本地预览构建 |
| `pnpm check` | 运行 Astro 错误检查 |
| `pnpm format` | 使用 Biome 格式化代码 |
| `pnpm lint` | 检查并修复代码问题 |
| `pnpm new-post <文件名>` | 创建新博客文章 |
| `pnpm astro ...` | 运行 Astro CLI 命令 |
## 🎯 配置指南
### 🔧 基础配置
编辑 `src/config.ts` 自定义您的博客:
```typescript
export const siteConfig: SiteConfig = {
title: "您的博客名称",
subtitle: "您的博客描述",
lang: "zh-CN", // 或 "en"、"ja" 等
themeColor: {
hue: 210, // 0-360主题色调
fixed: false, // 隐藏主题色选择器
},
banner: {
enable: true,
src: ["assets/banner/1.webp"], // 横幅图片
carousel: {
enable: true,
interval: 0.8, // 秒
},
},
};
```
### 📱 特色页面配置
- **追番页面:** 在 `src/pages/anime.astro` 中编辑动画列表
- **友链页面:** 在 `src/content/spec/friends.md` 中编辑朋友数据
- **日记页面:** 在 `src/pages/diary.astro` 中编辑动态
- **关于页面:** 在 `src/content/spec/about.md` 中编辑内容
### 📦 代码内容分离 (可选)
Mizuki 支持将代码和内容分成两个独立的仓库管理,适合团队协作和大型项目。
**快速选择**:
| 使用场景 | 配置方式 | 适合人群 |
|---------|---------|---------|
| 🆕 **本地模式** (默认) | 不配置,直接使用 | 新手、个人博客 |
| 🔧 **分离模式** | 设置 `ENABLE_CONTENT_SYNC=true` | 团队协作、私有内容 |
**一键启用/禁用**:
```bash
# 方式 1: 本地模式 (推荐新手)
# 不创建 .env 文件,直接运行
pnpm dev
# 方式 2: 内容分离模式
# 1. 复制配置文件
cp .env.example .env
# 2. 编辑 .env,启用内容分离
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
# 3. 同步内容
pnpm run sync-content
```
**功能特性**:
- ✅ 支持公开和私有仓库 🔐
- ✅ 一键启用/禁用,无需修改代码
- ✅ 自动同步,开发前自动拉取最新内容
📖 **详细配置**: [内容分离完整指南](docs/CONTENT_SEPARATION.md)
🔄 **迁移教程**: [从单仓库迁移到分离模式](docs/MIGRATION_GUIDE.md)
📚 **更多文档**: [文档索引](docs/README.md)
## ✏️ 贡献
我们欢迎贡献!请随时提交问题和拉取请求。
1. Fork 仓库
2. 创建功能分支 (`git checkout -b feature/amazing-feature`)
3. 提交更改 (`git commit -m 'Add some amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 打开拉取请求
## 📄 许可证
本项目基于 Apache 许可证 2.0 - 查看 [LICENSE](LICENSE) 文件了解详情。
### 原始项目许可证
本项目基于 [Fuwari](https://github.com/saicaca/fuwari) 开发,该项目使用 MIT 许可证。根据 MIT 许可证要求,原始版权声明和许可声明已包含在 LICENSE.MIT 文件中。
## 🙏 致谢
- 基于原始 [Fuwari](https://github.com/saicaca/fuwari) 模板
- 灵感来源于 [Yukina](https://github.com/WhitePaper233/yukina) - 一个美丽优雅的博客模板
- 部分设计来源于 [Firefly](https://github.com/CuteLeaf/Firefly) 模板
- 使用 [Pio](https://github.com/Dreamer-Paul/Pio) 实现可爱的 Live2D 看板娘插件
- 使用 [Astro](https://astro.build) 和 [Tailwind CSS](https://tailwindcss.com) 构建
- 图标来自 [Iconify](https://iconify.design/)
### 🌸 特别感谢
- **[Fuwari](https://github.com/saicaca/fuwari)** by saicaca - 本项目所基于的原始模板。感谢您创建了如此漂亮且功能强大的模板。
- **[Yukina](https://github.com/WhitePaper233/yukina)** - 感谢提供设计灵感和创意帮助塑造了这个项目。Yukina 是一个优雅的博客模板,展现了出色的设计原则和用户体验。
- **[Firefly](https://github.com/CuteLeaf/Firefly)** - 感谢提供优秀的布局设计思路,双侧边栏布局、文章双列网格等布局,及部分小组件的设计与实现,让 Mizuki 的界面更加丰富。
## 🍀 贡献者
感谢以下贡献者对本项目做出的贡献,如有问题或建议,请提交 [Issue](https://github.com/matsuzaka-yuki/Mizuki/issues) 或 [Pull Request](https://github.com/matsuzaka-yuki/Mizuki/pulls)。
<a href="https://github.com/matsuzaka-yuki/Mizuki/graphs/contributors">
<img src="https://contrib.rocks/image?repo=matsuzaka-yuki/Mizuki" />
</a>
## ⭐ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=matsuzaka-yuki/Mizuki&type=Date)](https://star-history.com/#matsuzaka-yuki/Mizuki&Date)
---
⭐ 如果您觉得这个项目有帮助,请考虑给它一个星标!

67
_frontmatter.json Normal file
View File

@@ -0,0 +1,67 @@
{
"$schema": "https://frontmatter.codes/frontmatter.schema.json",
"frontMatter.framework.id": "astro",
"frontMatter.preview.host": "http://localhost:4321",
"frontMatter.content.publicFolder": "public",
"frontMatter.content.pageFolders": [
{
"title": "posts",
"path": "[[workspace]]/src/content/posts"
}
],
"frontMatter.taxonomy.contentTypes": [
{
"name": "default",
"pageBundle": true,
"previewPath": "'blog'",
"filePrefix": null,
"clearEmpty": true,
"fields": [
{
"title": "title",
"name": "title",
"type": "string",
"single": true
},
{
"title": "description",
"name": "description",
"type": "string"
},
{
"title": "published",
"name": "published",
"type": "datetime",
"default": "{{now}}",
"isPublishDate": true
},
{
"title": "preview",
"name": "image",
"type": "image",
"isPreviewImage": true
},
{
"title": "tags",
"name": "tags",
"type": "list"
},
{
"title": "category",
"name": "category",
"type": "string"
},
{
"title": "draft",
"name": "draft",
"type": "boolean"
},
{
"title": "language",
"name": "language",
"type": "string"
}
]
}
]
}

198
astro.config.mjs Normal file
View File

@@ -0,0 +1,198 @@
import sitemap from "@astrojs/sitemap";
import svelte from "@astrojs/svelte";
import tailwind from "@astrojs/tailwind";
import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections";
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
import swup from "@swup/astro";
import { defineConfig } from "astro/config";
import expressiveCode from "astro-expressive-code";
import icon from "astro-icon";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeComponents from "rehype-components"; /* Render the custom directive content */
import rehypeKatex from "rehype-katex";
import rehypeSlug from "rehype-slug";
import remarkDirective from "remark-directive"; /* Handle directives */
import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives";
import remarkMath from "remark-math";
import remarkSectionize from "remark-sectionize";
import { expressiveCodeConfig, siteConfig } from "./src/config.ts";
import { pluginCustomCopyButton } from "./src/plugins/expressive-code/custom-copy-button.js";
import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge.ts";
import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs";
import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs";
import { rehypeMermaid } from "./src/plugins/rehype-mermaid.mjs";
import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js";
import { remarkExcerpt } from "./src/plugins/remark-excerpt.js";
import { remarkMermaid } from "./src/plugins/remark-mermaid.js";
import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs";
// https://astro.build/config
export default defineConfig({
site: siteConfig.siteURL,
base: "/",
trailingSlash: "always",
integrations: [
tailwind({
nesting: true,
}),
swup({
theme: false,
animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector
// the default value `transition-` cause transition delay
// when the Tailwind class `transition-all` is used
containers: ["main"],
smoothScrolling: false, // 禁用平滑滚动以提升性能,避免与锚点导航冲突
cache: true,
preload: false, // 禁用预加载以减少网络请求
accessibility: true,
updateHead: true,
updateBodyClass: false,
globalInstance: true,
// 滚动相关配置优化
resolveUrl: (url) => url,
animateHistoryBrowsing: false,
skipPopStateHandling: (event) => {
// 跳过锚点链接的处理,让浏览器原生处理
return event.state && event.state.url && event.state.url.includes("#");
},
}),
icon({
include: {
"preprocess: vitePreprocess(),": ["*"],
"fa6-brands": ["*"],
"fa6-regular": ["*"],
"fa6-solid": ["*"],
mdi: ["*"],
"simple-icons": ["*"],
},
}),
expressiveCode({
themes: ["github-light", "github-dark"],
plugins: [
pluginCollapsibleSections(),
pluginLineNumbers(),
pluginLanguageBadge(),
pluginCustomCopyButton(),
],
defaultProps: {
wrap: true,
overridesByLang: {
shellsession: {
showLineNumbers: false,
},
bash: {
frame: "code",
},
shell: {
frame: "code",
},
sh: {
frame: "code",
},
zsh: {
frame: "code",
},
},
},
styleOverrides: {
codeBackground: "var(--codeblock-bg)",
borderRadius: "0.75rem",
borderColor: "none",
codeFontSize: "0.875rem",
codeFontFamily:
"'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
codeLineHeight: "1.5rem",
frames: {
editorBackground: "var(--codeblock-bg)",
terminalBackground: "var(--codeblock-bg)",
terminalTitlebarBackground: "var(--codeblock-bg)",
editorTabBarBackground: "var(--codeblock-bg)",
editorActiveTabBackground: "none",
editorActiveTabIndicatorBottomColor: "var(--primary)",
editorActiveTabIndicatorTopColor: "none",
editorTabBarBorderBottomColor: "var(--codeblock-bg)",
terminalTitlebarBorderBottomColor: "none",
},
textMarkers: {
delHue: 0,
insHue: 180,
markHue: 250,
},
},
frames: {
showCopyToClipboardButton: false,
},
}),
svelte(),
sitemap(),
],
markdown: {
remarkPlugins: [
remarkMath,
remarkReadingTime,
remarkExcerpt,
remarkGithubAdmonitionsToDirectives,
remarkDirective,
remarkSectionize,
parseDirectiveNode,
remarkMermaid,
],
rehypePlugins: [
rehypeKatex,
rehypeSlug,
rehypeMermaid,
[
rehypeComponents,
{
components: {
github: GithubCardComponent,
note: (x, y) => AdmonitionComponent(x, y, "note"),
tip: (x, y) => AdmonitionComponent(x, y, "tip"),
important: (x, y) => AdmonitionComponent(x, y, "important"),
caution: (x, y) => AdmonitionComponent(x, y, "caution"),
warning: (x, y) => AdmonitionComponent(x, y, "warning"),
},
},
],
[
rehypeAutolinkHeadings,
{
behavior: "append",
properties: {
className: ["anchor"],
},
content: {
type: "element",
tagName: "span",
properties: {
className: ["anchor-icon"],
"data-pagefind-ignore": true,
},
children: [
{
type: "text",
value: "#",
},
],
},
},
],
],
},
vite: {
build: {
rollupOptions: {
onwarn(warning, warn) {
// temporarily suppress this warning
if (
warning.message.includes("is dynamically imported by") &&
warning.message.includes("but also statically imported by")
) {
return;
}
warn(warning);
},
},
},
},
});

63
biome.json Normal file
View File

@@ -0,0 +1,63 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"includes": [
"**",
"!**/src/**/*.css",
"!**/src/public/**/*",
"!**/dist/**/*",
"!**/node_modules/**/*"
]
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
},
"assist": { "actions": { "source": { "organizeImports": "on" } } },
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"noParameterAssign": "error",
"useAsConstAssertion": "error",
"useDefaultParameterLast": "error",
"useEnumInitializers": "error",
"useSelfClosingElements": "error",
"useSingleVarDeclarator": "error",
"noUnusedTemplateLiteral": "error",
"useNumberNamespace": "error",
"noInferrableTypes": "error",
"noUselessElse": "error"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"overrides": [
{
"includes": ["**/*.svelte", "**/*.astro", "**/*.vue"],
"linter": {
"rules": {
"style": {
"useConst": "off",
"useImportType": "off"
},
"correctness": {
"noUnusedVariables": "off",
"noUnusedImports": "off"
}
}
}
}
]
}

181
configuration.svg Normal file
View File

@@ -0,0 +1,181 @@
<svg width="800" height="1000" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
.title { font-family: Arial, sans-serif; font-size: 18px; font-weight: bold; fill: #2563eb; }
.subtitle { font-family: Arial, sans-serif; font-size: 14px; font-weight: bold; fill: #374151; }
.text { font-family: Arial, sans-serif; font-size: 12px; fill: #374151; }
.small-text { font-family: Arial, sans-serif; font-size: 10px; fill: #6b7280; }
.box { fill: #f3f4f6; stroke: #d1d5db; stroke-width: 2; rx: 8; }
.config-box { fill: #dbeafe; stroke: #3b82f6; stroke-width: 2; rx: 8; }
.process-box { fill: #dcfce7; stroke: #16a34a; stroke-width: 2; rx: 8; }
.component-box { fill: #fef3c7; stroke: #f59e0b; stroke-width: 2; rx: 8; }
.decision-diamond { fill: #fce7f3; stroke: #ec4899; stroke-width: 2; }
.arrow { stroke: #374151; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
.arrow-success { stroke: #16a34a; stroke-width: 2; fill: none; marker-end: url(#arrowhead-success); }
.arrow-error { stroke: #dc2626; stroke-width: 2; fill: none; marker-end: url(#arrowhead-error); }
</style>
<!-- Arrow markers -->
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#374151" />
</marker>
<marker id="arrowhead-success" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#16a34a" />
</marker>
<marker id="arrowhead-error" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#dc2626" />
</marker>
</defs>
<!-- Title -->
<text x="400" y="30" text-anchor="middle" class="title">组件配置加载流程图</text>
<text x="400" y="50" text-anchor="middle" class="small-text">Widget Configuration Loading Flowchart</text>
<!-- Start -->
<ellipse cx="400" cy="90" rx="60" ry="25" class="box" />
<text x="400" y="95" text-anchor="middle" class="subtitle">开始</text>
<!-- Load Config Files -->
<rect x="320" y="140" width="160" height="60" class="config-box" />
<text x="400" y="160" text-anchor="middle" class="subtitle">加载配置文件</text>
<text x="400" y="175" text-anchor="middle" class="text">src/config.ts</text>
<text x="400" y="190" text-anchor="middle" class="text">src/types/config.ts</text>
<!-- Initialize Widget Manager -->
<rect x="320" y="230" width="160" height="60" class="process-box" />
<text x="400" y="250" text-anchor="middle" class="subtitle">初始化组件管理器</text>
<text x="400" y="265" text-anchor="middle" class="text">WidgetManager</text>
<text x="400" y="280" text-anchor="middle" class="text">加载 sidebarLayoutConfig</text>
<!-- Validate Configuration -->
<polygon points="400,320 460,350 400,380 340,350" class="decision-diamond" />
<text x="400" y="345" text-anchor="middle" class="text">配置</text>
<text x="400" y="360" text-anchor="middle" class="text">验证</text>
<!-- Error Handling -->
<rect x="520" y="320" width="120" height="60" class="box" style="fill: #fee2e2; stroke: #dc2626;" />
<text x="580" y="340" text-anchor="middle" class="subtitle">错误处理</text>
<text x="580" y="355" text-anchor="middle" class="text">显示错误信息</text>
<text x="580" y="370" text-anchor="middle" class="text">使用默认配置</text>
<!-- Filter Enabled Components -->
<rect x="320" y="420" width="160" height="60" class="process-box" />
<text x="400" y="440" text-anchor="middle" class="subtitle">筛选启用组件</text>
<text x="400" y="455" text-anchor="middle" class="text">enable: true</text>
<text x="400" y="470" text-anchor="middle" class="text">响应式检查</text>
<!-- Sort Components -->
<rect x="320" y="510" width="160" height="60" class="process-box" />
<text x="400" y="530" text-anchor="middle" class="subtitle">组件排序</text>
<text x="400" y="545" text-anchor="middle" class="text">按 order 排序</text>
<text x="400" y="560" text-anchor="middle" class="text">按 position 分组</text>
<!-- Group by Position -->
<rect x="200" y="600" width="140" height="60" class="component-box" />
<text x="270" y="620" text-anchor="middle" class="subtitle">Top 组件</text>
<text x="270" y="635" text-anchor="middle" class="text">position: 'top'</text>
<text x="270" y="650" text-anchor="middle" class="text">固定在顶部</text>
<rect x="460" y="600" width="140" height="60" class="component-box" />
<text x="530" y="620" text-anchor="middle" class="subtitle">Sticky 组件</text>
<text x="530" y="635" text-anchor="middle" class="text">position: 'sticky'</text>
<text x="530" y="650" text-anchor="middle" class="text">粘性定位</text>
<!-- Load Components -->
<rect x="320" y="700" width="160" height="60" class="process-box" />
<text x="400" y="720" text-anchor="middle" class="subtitle">动态加载组件</text>
<text x="400" y="735" text-anchor="middle" class="text">componentMap 映射</text>
<text x="400" y="750" text-anchor="middle" class="text">Astro 组件导入</text>
<!-- Apply Styles and Animations -->
<rect x="320" y="790" width="160" height="60" class="process-box" />
<text x="400" y="810" text-anchor="middle" class="subtitle">应用样式和动画</text>
<text x="400" y="825" text-anchor="middle" class="text">CSS 类名生成</text>
<text x="400" y="840" text-anchor="middle" class="text">动画延迟计算</text>
<!-- Render Components -->
<rect x="320" y="880" width="160" height="60" class="component-box" />
<text x="400" y="900" text-anchor="middle" class="subtitle">渲染组件</text>
<text x="400" y="915" text-anchor="middle" class="text">DynamicSideBar.astro</text>
<text x="400" y="930" text-anchor="middle" class="text">DOM 输出</text>
<!-- End -->
<ellipse cx="400" cy="980" rx="60" ry="25" class="box" />
<text x="400" y="985" text-anchor="middle" class="subtitle">完成</text>
<!-- Arrows -->
<line x1="400" y1="115" x2="400" y2="140" class="arrow" />
<line x1="400" y1="200" x2="400" y2="230" class="arrow" />
<line x1="400" y1="290" x2="400" y2="320" class="arrow" />
<!-- Decision arrows -->
<line x1="460" y1="350" x2="520" y2="350" class="arrow-error" />
<text x="490" y="345" text-anchor="middle" class="small-text">失败</text>
<line x1="400" y1="380" x2="400" y2="420" class="arrow-success" />
<text x="420" y="400" text-anchor="middle" class="small-text">成功</text>
<!-- Error recovery -->
<line x1="580" y1="380" x2="580" y2="400" class="arrow" />
<line x1="580" y1="400" x2="400" y2="400" class="arrow" />
<line x1="400" y1="480" x2="400" y2="510" class="arrow" />
<line x1="400" y1="570" x2="400" y2="590" class="arrow" />
<!-- Split to position groups -->
<line x1="350" y1="590" x2="270" y2="600" class="arrow" />
<line x1="450" y1="590" x2="530" y2="600" class="arrow" />
<!-- Merge from position groups -->
<line x1="270" y1="660" x2="350" y2="690" class="arrow" />
<line x1="530" y1="660" x2="450" y2="690" class="arrow" />
<line x1="400" y1="760" x2="400" y2="790" class="arrow" />
<line x1="400" y1="850" x2="400" y2="880" class="arrow" />
<line x1="400" y1="940" x2="400" y2="955" class="arrow" />
<!-- Side annotations -->
<g transform="translate(50, 200)">
<rect x="0" y="0" width="200" height="120" class="box" style="fill: #f9fafb; stroke: #e5e7eb; stroke-dasharray: 5,5;" />
<text x="100" y="20" text-anchor="middle" class="subtitle">配置文件结构</text>
<text x="10" y="40" class="small-text">• SidebarLayoutConfig</text>
<text x="10" y="55" class="small-text">• WidgetComponentConfig[]</text>
<text x="10" y="70" class="small-text">• 响应式断点设置</text>
<text x="10" y="85" class="small-text">• 动画配置</text>
<text x="10" y="100" class="small-text">• 自定义属性</text>
</g>
<g transform="translate(550, 450)">
<rect x="0" y="0" width="200" height="140" class="box" style="fill: #f9fafb; stroke: #e5e7eb; stroke-dasharray: 5,5;" />
<text x="100" y="20" text-anchor="middle" class="subtitle">组件类型</text>
<text x="10" y="40" class="small-text">• profile (用户资料)</text>
<text x="10" y="55" class="small-text">• announcement (公告)</text>
<text x="10" y="70" class="small-text">• categories (分类)</text>
<text x="10" y="85" class="small-text">• tags (标签)</text>
<text x="10" y="100" class="small-text">• toc (目录)</text>
<text x="10" y="115" class="small-text">• music-player (音乐)</text>
<text x="10" y="130" class="small-text">• custom (自定义)</text>
</g>
<g transform="translate(50, 700)">
<rect x="0" y="0" width="200" height="100" class="box" style="fill: #f9fafb; stroke: #e5e7eb; stroke-dasharray: 5,5;" />
<text x="100" y="20" text-anchor="middle" class="subtitle">响应式检查</text>
<text x="10" y="40" class="small-text">• 获取当前设备类型</text>
<text x="10" y="55" class="small-text">• 检查断点配置</text>
<text x="10" y="70" class="small-text">• 过滤不适用组件</text>
<text x="10" y="85" class="small-text">• 应用设备特定样式</text>
</g>
<!-- Legend -->
<g transform="translate(50, 850)">
<text x="0" y="0" class="subtitle">图例说明</text>
<rect x="0" y="10" width="20" height="15" class="config-box" />
<text x="25" y="22" class="small-text">配置相关</text>
<rect x="0" y="30" width="20" height="15" class="process-box" />
<text x="25" y="42" class="small-text">处理流程</text>
<rect x="100" y="10" width="20" height="15" class="component-box" />
<text x="125" y="22" class="small-text">组件相关</text>
<polygon points="100,35 110,40 100,45 90,40" class="decision-diamond" />
<text x="125" y="42" class="small-text">判断节点</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

125
docs/AUTO_BUILD_TRIGGER.md Normal file
View File

@@ -0,0 +1,125 @@
# 内容仓库更新自动触发构建 - 快速参考
## 🎯 问题
启用内容分离后,内容仓库 (Mizuki-Content) 更新不会自动触发代码仓库 (Mizuki) 的重新部署。
## ✅ 解决方案 (推荐)
使用 **Repository Dispatch** 让内容更新时自动触发构建,适用于所有部署平台。
---
## 📝 5 步快速配置
### Step 1: 创建 GitHub Token
访问: https://github.com/settings/tokens
- 点击 **Generate new token (classic)**
- Note: `Mizuki Content Trigger`
- Scopes: 勾选 ✅ `repo`
- 点击生成并**复制 Token** ⚠️ (只显示一次)
### Step 2: 添加 Secret
在**内容仓库** (Mizuki-Content):
Settings → Secrets and variables → Actions → New repository secret
- Name: `DISPATCH_TOKEN`
- Secret: 粘贴刚才的 Token
### Step 3: 修改触发器配置
编辑内容仓库的 `.github/workflows/trigger-build.yml`
找到第 27 行,修改为你的代码仓库:
```yaml
repository: your-username/Mizuki # 改为你的
```
例如: `matsuzaka-yuki/Mizuki`
### Step 4: 更新代码仓库工作流
编辑**代码仓库**的 `.github/workflows/deploy.yml`
`on:` 部分添加:
```yaml
on:
push:
branches:
- main
repository_dispatch: # 👈 添加这个
types:
- content-updated
workflow_dispatch:
```
### Step 5: 测试
在内容仓库推送一次:
```bash
git add .
git commit -m "test: trigger build"
git push
```
查看:
1. 内容仓库 Actions - 确认触发器运行
2. 代码仓库 Actions - 确认部署被触发
---
## 🔍 故障排查
### Token 问题
**错误**: `Bad credentials`
**解决**:
- 确认 Token 复制完整
- 确认 Token 有 `repo` 权限
- 重新生成 Token
### 仓库名称问题
**错误**: `Not Found`
**解决**:
- 确认格式: `owner/repo` (用斜杠分隔)
- 确认拼写正确
- 示例: `matsuzaka-yuki/Mizuki`
### 代码仓库未触发
**检查**:
- [ ] `.github/workflows/deploy.yml` 包含 `repository_dispatch`
- [ ] Event type 为 `content-updated`
- [ ] 代码仓库 Actions 已启用
---
## 📚 详细文档
需要更多配置选项? 查看:
- [部署指南 - 完整说明](./DEPLOYMENT.md#内容仓库更新触发构建) - 包含 Webhook、定时构建等其他方案
- [内容仓库配置指南](../Mizuki-Content/.github/workflows/README.md) - 工作流详细说明
---
## 💡 提示
配置成功后:
- ✅ 内容仓库每次推送都会自动触发部署
- ✅ 可在 Actions 页面查看触发历史
- ✅ 支持手动触发 (workflow_dispatch)
---
**配置时间**: 约 5 分钟
**一次配置,长期有效**

255
docs/CONTENT_REPOSITORY.md Normal file
View File

@@ -0,0 +1,255 @@
# Mizuki 内容仓库结构说明
本文档说明如何创建和组织 Mizuki 博客的内容仓库。
## 📁 推荐的目录结构
```
Mizuki-Content/
├── posts/ # 博客文章
│ ├── post-1.md
│ ├── post-2.md
│ └── my-article/
│ ├── index.md
│ └── cover.jpg
├── spec/ # 特殊页面
│ ├── about.md
│ └── friends.md
├── data/ # 数据文件
│ ├── anime.ts
│ ├── projects.ts
│ ├── skills.ts
│ └── timeline.ts
├── images/ # 图片资源
│ ├── albums/ # 相册图片
│ ├── diary/ # 日记图片
│ └── posts/ # 文章图片
└── README.md
```
## 🚀 快速开始
### 1. 创建新的内容仓库
```bash
# 创建新仓库
mkdir Mizuki-Content
cd Mizuki-Content
git init
# 创建基本目录结构
mkdir -p posts spec data images/albums images/diary images/posts
# 创建 README
echo "# Mizuki 博客内容" > README.md
```
### 2. 从现有 Mizuki 项目迁移内容
如果你已经有一个 Mizuki 项目,可以将内容迁移到新仓库:
```bash
# 在 Mizuki 项目根目录执行
cd /path/to/Mizuki
# 复制内容到新仓库
cp -r src/content/posts/* /path/to/Mizuki-Content/posts/
cp -r src/content/spec/* /path/to/Mizuki-Content/spec/
cp -r src/data/* /path/to/Mizuki-Content/data/
cp -r public/images/* /path/to/Mizuki-Content/images/
```
### 3. 提交到 Git
```bash
cd /path/to/Mizuki-Content
git add .
git commit -m "Initial commit: Add blog content"
# 添加远程仓库并推送
git remote add origin https://github.com/your-username/Mizuki-Content.git
git branch -M main
git push -u origin main
```
## 🔗 连接到 Mizuki 代码仓库
### 方式一: Git Submodule (推荐)
在 Mizuki 代码仓库中:
```bash
cd /path/to/Mizuki
# 添加内容仓库作为 submodule
git submodule add https://github.com/your-username/Mizuki-Content.git content
# 提交 submodule 配置
git add .gitmodules content
git commit -m "Add content repository as submodule"
git push
```
配置环境变量 `.env`:
```bash
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=true
```
### 方式二: 独立仓库模式
配置环境变量 `.env`:
```bash
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
CONTENT_DIR=./content
USE_SUBMODULE=false
```
然后运行同步:
```bash
pnpm run sync-content
```
## 📝 内容编写指南
### 文章前言 (Frontmatter)
每篇文章都应该包含以下前言:
```yaml
---
title: 文章标题
published: 2024-01-01
description: 文章描述
image: ./cover.jpg
tags: [标签1, 标签2]
category: 分类
draft: false
pinned: false
lang: zh-CN
---
```
### 目录组织
- **单文件文章**: 直接在 `posts/` 目录下创建 `.md` 文件
- **包含图片的文章**: 创建文件夹,将 `index.md` 和图片放在一起
示例:
```
posts/
├── simple-post.md # 简单文章
└── complex-post/ # 复杂文章
├── index.md # 文章内容
├── cover.jpg # 封面图
└── diagram.png # 文章中的图片
```
## 🔄 更新工作流
### 本地开发
1. 修改内容仓库中的文件
2. 提交并推送更改
3. 在代码仓库中同步内容:
```bash
cd /path/to/Mizuki
pnpm run sync-content
```
### 使用 Submodule 时
```bash
# 更新 submodule
cd /path/to/Mizuki
git submodule update --remote --merge
# 或者使用同步脚本
pnpm run sync-content
```
### 部署时自动同步
在 CI/CD 配置中添加:
```yaml
- name: Sync Content
run: pnpm run sync-content
env:
CONTENT_REPO_URL: ${{ secrets.CONTENT_REPO_URL }}
USE_SUBMODULE: true
```
## 📦 数据文件说明
### anime.ts
番剧数据配置,包含你观看的动画列表。
### projects.ts
项目展示数据,展示你的作品集。
### skills.ts
技能数据,展示你的技术栈。
### timeline.ts
时间线数据,记录重要事件。
## 🎨 图片管理
### 目录说明
- `images/albums/`: 相册页面的图片
- `images/diary/`: 日记页面的图片
- `images/posts/`: 文章中引用的公共图片
### 图片引用
在文章中引用图片:
```markdown
<!-- 相对路径 (推荐) -->
![描述](./image.jpg)
<!-- 公共图片目录 -->
![描述](/images/posts/image.jpg)
```
## ⚠️ 注意事项
1. **不要**在内容仓库中包含代码文件
2. **保持**目录结构与主仓库一致
3. **定期**备份重要内容
4. **使用** Git LFS 管理大型图片文件(可选)
## 🔐 私有内容仓库
如果你的内容仓库是私有的,需要配置访问权限。详细的配置方法请参考:
- [内容分离完整指南 - 私有仓库配置](./CONTENT_SEPARATION.md#-私有仓库配置)
- [部署指南](./DEPLOYMENT.md) - 各平台的私有仓库部署配置
### 快速参考
**本地开发**: 推荐使用 SSH 密钥
```bash
CONTENT_REPO_URL=git@github.com:your-username/Mizuki-Content-Private.git
USE_SUBMODULE=true
```
**CI/CD 部署**: 根据平台选择
- GitHub Actions: 使用 `GITHUB_TOKEN` (同账号) 或 SSH 密钥
- Vercel/Netlify: 授权访问或使用 Token
## 📚 参考资源
- [Git Submodule 文档](https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97)
- [Mizuki 文档](https://docs.mizuki.mysqil.com/)
- [Astro Content Collections](https://docs.astro.build/zh-cn/guides/content-collections/)
---
💡 **提示**: 建议先在本地测试内容同步流程,确保一切正常后再配置自动化部署。

525
docs/CONTENT_SEPARATION.md Normal file
View File

@@ -0,0 +1,525 @@
# Mizuki 内容分离完整指南
本指南详细说明如何在 Mizuki 中使用内容分离功能,包括基础配置、私有仓库、CI/CD 部署等所有场景。
## 📖 目录
- [快速开始](#-快速开始)
- [ENABLE_CONTENT_SYNC 控制开关](#-enable_content_sync-控制开关)
- [配置方式](#-配置方式)
- [私有仓库](#-私有仓库配置)
- [CI/CD 部署](#-cicd-部署)
- [常用命令](#-常用命令)
- [故障排查](#-故障排查)
---
## 🚀 快速开始
### 新手推荐: 本地模式 (最简单)
**不需要任何配置**,直接开始使用:
```bash
# 克隆项目
git clone https://github.com/matsuzaka-yuki/Mizuki.git
cd Mizuki
# 安装依赖
pnpm install
# 直接开发
pnpm dev
```
内容存放在 `src/content/``public/images/` 目录,与代码一起管理。
### 进阶: 启用内容分离
如果需要将内容独立管理(多人协作、私有内容、独立版本控制),按以下步骤配置:
```bash
# 1. 创建 .env 文件
cp .env.example .env
# 2. 编辑 .env,启用内容分离
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
# 3. 同步内容
pnpm run sync-content
# 4. 启动开发
pnpm dev
```
---
## 🎛️ ENABLE_CONTENT_SYNC 控制开关
### 功能说明
`ENABLE_CONTENT_SYNC` 是一个一键开关,控制是否启用内容分离功能。
| 值 | 说明 | 适用场景 |
|---|---|---|
| `false` 或未设置 | **禁用内容分离** (默认) | 新手、个人博客、内容较少 |
| `true` | **启用内容分离** | 团队协作、私有内容、大量文章 |
### 配置位置
在项目根目录的 `.env` 文件中:
```bash
# 禁用内容分离 (使用本地内容)
ENABLE_CONTENT_SYNC=false
# 或启用内容分离 (从远程仓库同步)
ENABLE_CONTENT_SYNC=true
```
### 使用场景对比
#### 场景 1: 本地模式 (推荐新手)
**特点**:
- ✅ 无需额外配置
- ✅ 内容和代码一起管理
- ✅ 适合个人博客、小型项目
**配置**:
```bash
# .env (或不创建 .env 文件)
ENABLE_CONTENT_SYNC=false
```
**工作流程**:
```bash
# 直接编辑 src/content/ 下的文章
pnpm dev
# 提交时一起提交代码和内容
git add .
git commit -m "Update content"
git push
```
#### 场景 2: 独立仓库(分离)模式
**特点**:
- ✅ 内容独立仓库管理
- ✅ 支持私有内容仓库
- ✅ 多人协作方便
- ✅ 独立的内容版本控制
**配置**:
```bash
# .env
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
```
**工作流程**:
```bash
# 自动同步内容后启动
pnpm dev
# 内容在独立仓库编辑
cd /path/to/Mizuki-Content
# 编辑文章
git add .
git commit -m "Update article"
git push
```
### 模式切换
#### 从本地切换到独立仓库
1. 创建内容仓库 (参考 [CONTENT_MIGRATION.md](./CONTENT_MIGRATION.md))
2. 编辑 `.env`:
```bash
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
```
3. 同步内容: `pnpm run sync-content`
#### 从独立仓库切换回本地
1. 编辑 `.env`:
```bash
ENABLE_CONTENT_SYNC=false
```
2. 直接开发: `pnpm dev`
---
## ⚙️ 配置方式
### 环境变量说明
在 `.env` 文件中配置:
```bash
# ============================================
# 功能开关
# ============================================
# 是否启用内容分离功能
# false = 使用本地内容 (推荐新手)
# true = 从远程仓库同步内容
ENABLE_CONTENT_SYNC=false
# ============================================
# 内容仓库配置 (仅当 ENABLE_CONTENT_SYNC=true 时需要)
# ============================================
# 内容仓库地址
# 支持 HTTPS 和 SSH 方式
# 公开仓库: https://github.com/username/repo.git
# 私有仓库 (SSH): git@github.com:username/repo.git
# 私有仓库 (Token): https://TOKEN@github.com/username/repo.git
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
# 内容目录路径 (默认 ./content 一般无需改动)
CONTENT_DIR=./content
```
### 配置示例
#### 示例 1: 完全本地 (最简单)
```bash
# .env
ENABLE_CONTENT_SYNC=false
```
或者**不创建 `.env` 文件**,直接使用本地内容。
#### 示例 2: 公开仓库 (HTTPS)
```bash
# .env
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
```
#### 示例 3: 私有仓库 (SSH)
```bash
# .env
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=git@github.com:your-username/Mizuki-Content-Private.git
```
---
## 🔄 自动构建触发 (内容更新时)
### 问题
启用内容分离后,默认只有代码仓库更新会触发部署,内容仓库更新**不会**自动触发。
### 解决方案
**推荐使用 Repository Dispatch**5 步快速配置,适用所有部署平台。
详细步骤请查看:
- **[自动构建触发快速参考](./AUTO_BUILD_TRIGGER.md)** - 最简洁的配置指南 ⭐
- **[部署文档 - 完整说明](./DEPLOYMENT.md#内容仓库更新触发构建)** - 包含多种方案
- **[内容仓库配置指南](../Mizuki-Content/.github/workflows/README.md)** - 工作流详细说明
---
## 🔐 私有仓库配置
完全支持私有内容仓库! 推荐使用 SSH 方式,安全且方便。
### 方案 A: SSH 密钥 (推荐)
#### 1. 生成 SSH 密钥
```bash
# 推荐使用 Ed25519
ssh-keygen -t ed25519 -C "your_email@example.com"
# 或使用 RSA
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```
按提示操作,默认保存到 `~/.ssh/id_ed25519`。
#### 2. 添加公钥到 Git 平台
```bash
# 查看公钥
cat ~/.ssh/id_ed25519.pub
# Windows PowerShell
Get-Content ~/.ssh/id_ed25519.pub
```
**GitHub**:
- Settings → SSH and GPG keys → New SSH key
- 粘贴公钥内容
**GitLab**:
- Preferences → SSH Keys → Add new key
**Gitee**:
- 设置 → SSH 公钥 → 添加公钥
#### 3. 配置 Mizuki
在 `.env` 文件中使用 SSH URL:
```bash
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=git@github.com:your-username/Mizuki-Content-Private.git
```
#### 4. 测试连接
```bash
# 测试 GitHub 连接
ssh -T git@github.com
# 测试 GitLab 连接
ssh -T git@gitlab.com
# 同步内容
pnpm run sync-content
```
### 方案 B: HTTPS + Personal Access Token
#### 1. 生成 Token
**GitHub**:
- Settings → Developer settings → Personal access tokens → Generate new token
- 权限: 勾选 `repo` (完整访问)
**GitLab**:
- Preferences → Access Tokens
- Scopes: `read_repository`
**Gitee**:
- 设置 → 私人令牌 → 生成新令牌
- 权限: `projects` (读取)
#### 2. 配置 .env
```bash
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://YOUR_TOKEN@github.com/your-username/Mizuki-Content-Private.git
```
⚠️ **安全提示**:
- **不要将 `.env` 提交到 Git!** (已在 `.gitignore` 中)
- Token 具有完整权限,请妥善保管
---
## 🌐 CI/CD 部署
### 快速配置
所有部署平台都使用相同的自动同步机制:
- ✅ `pnpm build` 执行前自动运行 `prebuild` 钩子
- ✅ 根据 `ENABLE_CONTENT_SYNC` 决定是否同步内容
- ✅ 同步失败不会中断构建,回退到本地内容
**只需配置环境变量,无需修改构建命令!**
### 环境变量配置
在部署平台添加以下环境变量:
| 变量名 | 值 | 说明 |
|-------|---|------|
| `ENABLE_CONTENT_SYNC` | `true` | 启用内容分离 |
| `CONTENT_REPO_URL` | 仓库地址 | 内容仓库的 URL |
### 支持的平台
- ✅ **GitHub Pages** - 使用 GitHub Actions
- ✅ **Vercel** - 环境变量配置
- ✅ **Netlify** - 环境变量配置
- ✅ **Cloudflare Pages** - 环境变量配置
### 详细配置指南
不同平台的具体配置步骤、私有仓库认证、故障排查等详细信息,请查看:
📖 **[部署指南](./DEPLOYMENT.md)** - 完整的部署文档,包含:
- GitHub Pages 自动部署配置
- Vercel 部署详细步骤
- Netlify 部署配置
- Cloudflare Pages 部署
- 私有仓库认证配置
- 常见问题故障排查
---
## 📋 常用命令
| 命令 | 说明 |
|------|------|
| `pnpm run init-content` | 运行交互式初始化向导 |
| `pnpm run sync-content` | 手动同步内容仓库 |
| `pnpm run check-env` | 检查环境变量配置 |
| `pnpm dev` | 启动开发服务器 (自动同步) |
| `pnpm build` | 构建项目 (自动同步) |
### 自动同步时机
当 `ENABLE_CONTENT_SYNC=true` 时,以下命令会自动同步内容:
- `pnpm dev` - 开发前自动同步
- `pnpm build` - 构建前自动同步
同步失败不会中断开发,会显示警告并继续。
---
## 🔍 故障排查
### 问题 1: 提示 "未启用内容分离功能"
**原因**: `ENABLE_CONTENT_SYNC` 未设置或设置为 `false`。
**解决**:
```bash
# 检查 .env 文件
cat .env
# 确认有以下配置
ENABLE_CONTENT_SYNC=true
```
### 问题 2: 提示 "未设置 CONTENT_REPO_URL"
**原因**: 启用了内容分离但未配置仓库地址。
**解决**:
```bash
# 在 .env 中添加
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
```
### 问题 3: 私有仓库认证失败
**SSH 方式**:
```bash
# 测试 SSH 连接
ssh -T git@github.com
# 应该看到: Hi username! You've successfully authenticated...
```
如果失败,检查:
- SSH 密钥是否生成: `ls ~/.ssh/`
- 公钥是否添加到 GitHub
- SSH agent 是否运行: `ssh-add -l`
**HTTPS + Token 方式**:
- 检查 Token 是否有效
- 检查 Token 权限是否正确 (`repo` 权限)
- 确认 URL 格式: `https://TOKEN@github.com/user/repo.git`
### 问题 4: .env 文件不生效
**检查清单**:
1. 文件位置正确 (项目根目录)
```bash
ls -la .env # Linux/Mac
dir .env # Windows
```
2. 文件格式正确
```bash
# ✅ 正确
ENABLE_CONTENT_SYNC=true
# ❌ 错误 (多余空格)
ENABLE_CONTENT_SYNC = true
# ❌ 错误 (不需要引号,除非值中有空格)
ENABLE_CONTENT_SYNC="true"
```
3. 文件权限可读
```bash
chmod 644 .env # Linux/Mac
```
4. 运行检查命令
```bash
pnpm run check-env
```
### 问题 5: 内容同步失败
```bash
# 手动同步内容
pnpm run sync-content
# 检查内容目录
ls -la content/
# 手动克隆内容仓库
git clone https://github.com/your-username/Mizuki-Content.git content
```
### 问题 6: 部署时内容未同步
**Vercel/Netlify**:
- 确认环境变量已添加
- 检查构建日志,查看同步步骤是否执行
- 确认 Token 在部署环境有效
**GitHub Actions**:
- 检查工作流配置
- 查看 Actions 运行日志
- 确认 Secrets 已正确添加
---
## 💡 最佳实践
### 新手建议
1. **从本地模式开始** - 不需要额外配置,立即可用
2. **内容稳定后再分离** - 等内容积累到一定程度
3. **使用 SSH 方式** - 比 Token 更安全方便
### 进阶用户
1. **使用独立仓库模式** - 清晰的版本控制
2. **内容仓库添加 CI** - 自动检查文章格式、图片优化等
3. **分支管理** - main 分支用于生产,develop 用于预览
### 团队协作
1. **统一环境变量** - 团队成员使用相同的配置
2. **权限控制** - 内容仓库设置为私有,精细控制访问权限
3. **Git Hooks** - 提交前检查文章格式、图片大小等
---
## 📚 相关文档
- [内容迁移指南](./CONTENT_MIGRATION.md) - 如何从单仓库迁移到分离模式
- [内容仓库结构](./CONTENT_REPOSITORY.md) - 内容仓库的推荐结构
- [主 README](../README.zh.md) - 项目总体说明
---
## 🤝 需要帮助?
- 查看 [GitHub Issues](https://github.com/matsuzaka-yuki/Mizuki/issues)
- 阅读 [完整文档](../README.zh.md)
- 运行 `pnpm run check-env` 检查配置
祝你使用愉快! 🎉

848
docs/DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,848 @@
# Mizuki 部署指南
本文档提供 Mizuki 博客在各个平台的部署配置说明。
## 📖 目录
- [部署前准备](#-部署前准备)
- [GitHub Pages 部署](#-github-pages-部署)
- [Vercel 部署](#-vercel-部署)
- [Netlify 部署](#-netlify-部署)
- [Cloudflare Pages 部署](#-cloudflare-pages-部署)
- [故障排查](#-故障排查)
---
## 🚀 部署前准备
### 基础配置
1. **更新站点 URL**
编辑 `astro.config.mjs`:
```javascript
export default defineConfig({
site: 'https://your-domain.com', // 更新为你的域名
// ...
});
```
2. **配置环境变量** (可选)
如果使用内容分离功能,需要配置:
- `ENABLE_CONTENT_SYNC=true`
- `CONTENT_REPO_URL=你的内容仓库地址`
- `USE_SUBMODULE=true`
详见 [内容分离完整指南](./CONTENT_SEPARATION.md)
---
## 📦 GitHub Pages 部署
### 自动部署 (推荐)
项目已配置好 GitHub Actions 工作流,推送到 `main` 分支会自动部署。
#### 本地模式 (默认)
**无需任何配置**,开箱即用:
1. 推送代码到 GitHub
2. 在仓库设置中启用 GitHub Pages
- Settings → Pages
- Source: Deploy from a branch
- Branch: `pages` / `root`
3. 等待 Actions 完成部署
#### 内容分离模式
**配置步骤**:
1. **添加仓库 Secrets**:
- Settings → Secrets and variables → Actions → New repository secret
- 添加 `CONTENT_REPO_URL`: `https://github.com/your-username/Mizuki-Content.git`
2. **修改 `.github/workflows/deploy.yml`**:
取消注释环境变量部分:
```yaml
- name: Build site
run: pnpm run build
env:
ENABLE_CONTENT_SYNC: true
CONTENT_REPO_URL: ${{ secrets.CONTENT_REPO_URL }}
USE_SUBMODULE: true
```
3. **私有内容仓库配置**:
**同账号私有仓库** (推荐):
- 无需额外配置
- 自动使用 `GITHUB_TOKEN` 访问
**跨账号私有仓库 (SSH)**:
```yaml
# 添加 SSH 配置步骤
- name: Setup SSH Key
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
```
在 Secrets 中添加:
- `SSH_PRIVATE_KEY`: SSH 私钥内容
- `CONTENT_REPO_URL`: `git@github.com:other-user/repo.git`
**跨账号私有仓库 (Token)**:
```yaml
- name: Checkout
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT_TOKEN }}
- name: Build site
run: pnpm run build
env:
ENABLE_CONTENT_SYNC: true
CONTENT_REPO_URL: https://${{ secrets.PAT_TOKEN }}@github.com/other-user/repo.git
USE_SUBMODULE: true
```
在 Secrets 中添加:
- `PAT_TOKEN`: GitHub Personal Access Token (需要 `repo` 权限)
### 工作流说明
项目包含三个工作流:
| 工作流 | 触发条件 | 功能 |
|--------|---------|------|
| `build.yml` | Push/PR 到 main | CI 测试,检查构建 |
| `deploy.yml` | Push 到 main | 构建并部署到 pages 分支 |
| `biome.yml` | Push/PR | 代码格式和质量检查 |
---
## 🔷 Vercel 部署
### 快速部署
1. **连接仓库**:
- 访问 [Vercel](https://vercel.com)
- Import Git Repository
- 选择你的 Mizuki 仓库
2. **配置项目**:
- Framework Preset: Astro
- Build Command: `pnpm build` (默认)
- Output Directory: `dist` (默认)
3. **部署**:
- 点击 Deploy 开始部署
### 部署模式
#### 本地模式
**无需配置环境变量**,使用默认的 `vercel.json`
#### 内容分离模式 - 公开仓库
在 Vercel 项目设置中添加环境变量:
| 变量名 | 值 |
|-------|---|
| `ENABLE_CONTENT_SYNC` | `true` |
| `CONTENT_REPO_URL` | `https://github.com/your-username/Mizuki-Content.git` |
| `USE_SUBMODULE` | `false``true` (推荐 `false`) |
> ⚠️ **重要提示**: 如果使用 `USE_SUBMODULE=true`,请确保 `.gitignore` 中的 `content/` 行已被注释掉,否则会导致部署失败。推荐在 Vercel 上使用 `USE_SUBMODULE=false` (独立仓库模式)。
#### 内容分离模式 - 私有仓库
**方式 A: 授权 Vercel 访问**
- 在连接 GitHub 仓库时,确保授权包括内容仓库的访问权限
**方式 B: 使用 Token**
添加环境变量:
```
ENABLE_CONTENT_SYNC=true
GITHUB_TOKEN=ghp_your_personal_access_token
CONTENT_REPO_URL=https://${GITHUB_TOKEN}@github.com/your-username/Mizuki-Content-Private.git
USE_SUBMODULE=true
```
### 配置文件
项目包含两个 Vercel 配置文件:
- `vercel.json` - 默认配置,适用于本地模式
- `vercel-with-content.json.example` - 内容分离示例 (可选)
**注意**: 使用默认 `vercel.json` 即可,通过环境变量控制是否启用内容分离。
---
## 🌐 Netlify 部署
### 部署步骤
1. **连接仓库**:
- 访问 [Netlify](https://www.netlify.com)
- New site from Git
- 选择你的 Mizuki 仓库
2. **配置构建**:
- Build command: `pnpm build`
- Publish directory: `dist`
3. **环境变量** (如果使用内容分离):
在 Site settings → Environment variables 中添加:
```
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=true
```
4. **私有仓库配置**:
在 Site settings → Build & deploy → Deploy key 中添加有权限访问私有仓库的 SSH 密钥。
### netlify.toml 配置
可选:创建 `netlify.toml` 文件:
```toml
[build]
command = "pnpm build"
publish = "dist"
[build.environment]
NODE_VERSION = "20"
PNPM_VERSION = "9"
# 如果使用内容分离
ENABLE_CONTENT_SYNC = "true"
CONTENT_REPO_URL = "https://github.com/your-username/Mizuki-Content.git"
USE_SUBMODULE = "true"
```
---
## ☁️ Cloudflare Pages 部署
### 部署步骤
1. **连接仓库**:
- 登录 [Cloudflare Dashboard](https://dash.cloudflare.com)
- Workers & Pages → Create application → Pages
- Connect to Git
2. **配置构建**:
- Framework preset: Astro
- Build command: `pnpm build`
- Build output directory: `dist`
3. **环境变量** (如果使用内容分离):
添加以下变量:
```
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=false # ⚠️ Cloudflare Pages 默认不支持 submodule
```
### 注意事项
⚠️ Cloudflare Pages 默认不支持 Git Submodule建议:
- 使用独立仓库模式: `USE_SUBMODULE=false`
- 或在构建命令中手动初始化: `git submodule update --init && pnpm build`
---
## 🔄 自动同步机制
所有部署平台都使用相同的自动同步机制:
```json
// package.json
{
"scripts": {
"prebuild": "node scripts/sync-content.js || true"
}
}
```
**工作原理**:
1. `pnpm build` 执行前自动运行 `prebuild` 钩子
2. 检查 `ENABLE_CONTENT_SYNC` 环境变量
3. 如果为 `true`,从远程仓库同步内容到 `src/content/``public/images/`
4. 如果为 `false` 或未设置,跳过同步,使用本地内容
5. `|| true` 确保同步失败不会中断构建
**优势**:
- ✅ 统一的构建命令,无需修改配置
- ✅ 自动兼容所有部署模式
- ✅ 同步失败不影响构建(回退到本地内容)
---
## 🔍 故障排查
### 问题 1: 部署失败 - "未设置 CONTENT_REPO_URL"
**原因**: 启用了内容分离但未配置仓库地址
**解决**:
1. 检查环境变量中是否设置了 `ENABLE_CONTENT_SYNC=true`
2. 检查是否设置了 `CONTENT_REPO_URL`
3. 或将 `ENABLE_CONTENT_SYNC` 设置为 `false` 使用本地内容
### 问题 2: 私有仓库认证失败
**GitHub Actions**:
- **同账号**: 确保使用 `${{ secrets.GITHUB_TOKEN }}`
- **跨账号**: 配置 SSH 密钥或 PAT Token
**Vercel/Netlify**:
- 确保授权了私有仓库访问
- 或使用 Token 方式: `https://TOKEN@github.com/user/repo.git`
### 问题 3: Submodule 与 .gitignore 冲突
**错误信息**:
```
The following paths are ignored by one of your .gitignore files:
content
fatal: Failed to add submodule 'content'
```
**原因**: `.gitignore` 文件中的 `content/` 规则阻止了 Git 添加 submodule
**解决方案 A: 修改 .gitignore (推荐)**
编辑 `.gitignore` 文件,注释掉或删除 `content/` 行:
```diff
# content repository (if using independent mode)
- content/
+ # content/ # 使用 submodule 时需要注释掉
*.backup
```
然后重新部署。
**解决方案 B: 使用独立仓库模式**
如果不想修改 `.gitignore`,可以使用独立仓库模式:
```
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=false # 改为 false
```
**解决方案 C: 自动降级 (v1.1+)**
`sync-content.js` 会自动检测此冲突并降级到独立仓库模式,无需手动干预。
### 问题 4: Submodule 克隆失败
**检查**:
1. 确认部署平台支持 Git Submodule
2. 检查 SSH 密钥或 Token 配置
3. 尝试使用独立仓库模式: `USE_SUBMODULE=false`
### 问题 5: 构建成功但内容未更新
**检查**:
1. 查看构建日志,确认同步步骤执行
2. 检查 `ENABLE_CONTENT_SYNC` 是否设置为 `true`
3. 验证 `CONTENT_REPO_URL` 是否正确
4. 清除部署平台的缓存并重新部署
### 问题 6: 部署时间过长
**优化建议**:
- 使用 Git Submodule 模式 (更快)
- 启用部署平台的缓存机制
- 优化图片大小和数量
### 问题 7: Vercel 部署时 submodule 权限问题
**错误信息**:
```
fatal: could not read Username for 'https://github.com'
```
**原因**: 私有仓库需要认证
**解决**:
1. 在 Vercel 项目设置中添加 GitHub 集成权限
2. 或使用 Token: `https://${GITHUB_TOKEN}@github.com/user/repo.git`
3. 或切换到独立仓库模式: `USE_SUBMODULE=false`
**检查**:
1. 查看构建日志,确认同步步骤执行
2. 检查 `ENABLE_CONTENT_SYNC` 是否设置为 `true`
3. 验证 `CONTENT_REPO_URL` 是否正确
4. 清除部署平台的缓存并重新部署
---
## 📋 环境变量参考
| 变量名 | 必需 | 默认值 | 说明 |
|-------|------|--------|------|
| `ENABLE_CONTENT_SYNC` | ❌ | `false` | 是否启用内容分离功能 |
| `CONTENT_REPO_URL` | ⚠️ | - | 内容仓库地址 (启用内容分离时必需) |
| `USE_SUBMODULE` | ❌ | `false` | 是否使用 Git Submodule 模式 |
| `CONTENT_DIR` | ❌ | `./content` | 内容目录路径 |
| `UMAMI_API_KEY` | ❌ | - | Umami 统计 API 密钥 |
| `BCRYPT_SALT_ROUNDS` | ❌ | `12` | bcrypt 加密轮数 |
⚠️ = 在特定模式下必需
---
## 💡 推荐配置
### 个人博客
- **平台**: Vercel 或 GitHub Pages
- **模式**: 本地模式(最简单)
- **配置**: 无需环境变量
### 团队协作
- **平台**: 任意
- **模式**: 内容分离 - 私有仓库
- **配置**: 启用内容分离 + SSH 认证
### 多站点部署
- **平台**: 多个平台同时部署
- **模式**: 内容分离 - 公开仓库
- **配置**: 统一的环境变量配置
---
## 📚 相关文档
- [内容分离完整指南](./CONTENT_SEPARATION.md) - 详细的内容分离配置
- [内容迁移指南](./MIGRATION_GUIDE.md) - 从单仓库迁移到分离模式
- [内容仓库结构](./CONTENT_REPOSITORY.md) - 内容仓库的组织方式
---
💡 **建议**: 如果是第一次部署,推荐先使用本地模式熟悉流程,之后再根据需要启用内容分离功能。
## 🔔 内容仓库更新触发构建
### 问题说明
当使用**内容代码分离**架构时,默认情况下:
- ✅ 代码仓库 (Mizuki) 更新会触发自动构建
- ❌ 内容仓库 (Mizuki-Content) 更新**不会**触发构建
这意味着您在内容仓库中发布新文章后,需要手动触发代码仓库的重新部署才能看到更新。
### 解决方案概览
有以下几种方式实现内容仓库更新时自动触发构建:
| 方案 | 难度 | 推荐度 | 适用平台 |
|------|------|--------|----------|
| **Repository Dispatch** | ⭐ 简单 | ⭐⭐⭐⭐⭐ | GitHub Pages, Vercel, Netlify, CF Pages |
| **Webhook + Deploy Hook** | ⭐⭐ 中等 | ⭐⭐⭐⭐ | Vercel, Netlify, CF Pages |
| **定时构建** | ⭐ 简单 | ⭐⭐⭐ | 所有平台 |
---
### 方案 1: Repository Dispatch (推荐)
**原理**: 内容仓库推送时,通过 GitHub Actions 触发代码仓库的构建工作流。
**优点**:
- ✅ 实时触发,无延迟
- ✅ 无需云平台特定配置
- ✅ 适用于所有部署平台
- ✅ 完全免费
#### 配置步骤
**Step 1: 创建 GitHub Personal Access Token (PAT)**
1. 访问 [GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)](https://github.com/settings/tokens)
2. 点击 **Generate new token (classic)**
3. 配置 Token:
- Note: `Mizuki Content Trigger` (名称随意)
- Expiration: `No expiration` 或选择合适的期限
- Scopes: 勾选 `repo` (完整仓库访问权限)
4. 点击 **Generate token**,复制生成的 Token (只显示一次!)
**Step 2: 在内容仓库添加 Secret**
1. 打开内容仓库 (Mizuki-Content): `https://github.com/your-username/Mizuki-Content`
2. Settings → Secrets and variables → Actions → New repository secret
3. 添加:
- Name: `DISPATCH_TOKEN`
- Value: 粘贴刚才创建的 PAT Token
4. 点击 **Add secret**
**Step 3: 在内容仓库创建 GitHub Actions 工作流**
在内容仓库创建文件 `.github/workflows/trigger-build.yml`:
```yaml
name: Trigger Main Repo Build
on:
push:
branches:
- main # 或你使用的主分支名称
paths:
- 'posts/**'
- 'spec/**'
- 'data/**'
- 'images/**'
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger repository dispatch
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.DISPATCH_TOKEN }}
repository: your-username/Mizuki # 改为你的代码仓库
event-type: content-updated
client-payload: |
{
"ref": "${{ github.ref }}",
"sha": "${{ github.sha }}",
"message": "${{ github.event.head_commit.message }}"
}
```
**注意事项**:
-`your-username/Mizuki` 替换为你的代码仓库完整名称
- 可以根据需要调整 `paths`,只在特定文件变化时触发
**Step 4: 在代码仓库更新 GitHub Actions 工作流**
编辑代码仓库的 `.github/workflows/deploy.yml`,添加 `repository_dispatch` 触发器:
```yaml
name: Deploy to GitHub Pages
on:
push:
branches:
- main
repository_dispatch: # 添加这个触发器
types:
- content-updated
# ...其余配置保持不变
```
**Step 5: 测试**
1. 在内容仓库编辑一篇文章
2. 提交并推送到 `main` 分支
3. 查看内容仓库的 Actions 页面,确认 "Trigger Main Repo Build" 工作流运行
4. 查看代码仓库的 Actions 页面,确认部署工作流被触发
---
### 方案 2: Webhook + Deploy Hook
**原理**: 使用云平台提供的 Deploy Hook URL在内容仓库更新时通过 webhook 触发构建。
**优点**:
- ✅ 实时触发
- ✅ 与部署平台深度集成
**缺点**:
- ⚠️ 需要为每个部署平台单独配置
- ⚠️ 不适用于 GitHub Pages
#### Vercel 配置
**Step 1: 获取 Deploy Hook URL**
1. 打开 Vercel 项目设置
2. Settings → Git → Deploy Hooks
3. 创建新的 Hook:
- Name: `Content Update`
- Git Branch: `main` (或你的主分支)
4. 点击 **Create Hook**,复制生成的 URL
**Step 2: 在内容仓库配置 Webhook**
在内容仓库创建 `.github/workflows/trigger-vercel.yml`:
```yaml
name: Trigger Vercel Deployment
on:
push:
branches:
- main
paths:
- 'posts/**'
- 'spec/**'
- 'data/**'
- 'images/**'
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Vercel Deploy Hook
run: |
curl -X POST "${{ secrets.VERCEL_DEPLOY_HOOK }}"
```
**Step 3: 添加 Secret**
在内容仓库添加 Secret:
- Name: `VERCEL_DEPLOY_HOOK`
- Value: 粘贴 Vercel Deploy Hook URL
#### Netlify 配置
**Step 1: 获取 Build Hook URL**
1. 打开 Netlify 站点设置
2. Site settings → Build & deploy → Continuous deployment → Build hooks
3. 点击 **Add build hook**:
- Build hook name: `Content Update`
- Branch to build: `main`
4. 保存并复制生成的 URL
**Step 2: 配置 GitHub Actions**
在内容仓库创建 `.github/workflows/trigger-netlify.yml`:
```yaml
name: Trigger Netlify Deployment
on:
push:
branches:
- main
paths:
- 'posts/**'
- 'spec/**'
- 'data/**'
- 'images/**'
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Netlify Build Hook
run: |
curl -X POST -d '{}' "${{ secrets.NETLIFY_BUILD_HOOK }}"
```
**Step 3: 添加 Secret**
- Name: `NETLIFY_BUILD_HOOK`
- Value: 粘贴 Netlify Build Hook URL
#### Cloudflare Pages 配置
**Step 1: 获取 Deploy Hook URL**
1. 打开 Cloudflare Pages 项目
2. Settings → Builds & deployments → Deploy hooks
3. 创建 Deploy Hook:
- Hook name: `Content Update`
- Branch: `main`
4. 保存并复制 URL
**Step 2: 配置类似于 Vercel/Netlify**
配置方式与上述相同,只需修改 Secret 名称和 workflow 文件名。
---
### 方案 3: 定时构建 (fallback)
**原理**: 设置定时任务,每天自动构建一次。
**优点**:
- ✅ 配置简单
- ✅ 无需额外 Token 或 Webhook
**缺点**:
- ⚠️ 有延迟,不是实时更新
- ⚠️ 可能造成不必要的构建
#### GitHub Actions 配置
在代码仓库的 `.github/workflows/deploy.yml` 中添加定时触发:
```yaml
name: Deploy to GitHub Pages
on:
push:
branches:
- main
schedule:
- cron: '0 2 * * *' # 每天凌晨 2 点 (UTC 时间)
workflow_dispatch: # 支持手动触发
# ...其余配置
```
**Cron 表达式示例**:
- `0 2 * * *` - 每天凌晨 2 点
- `0 */6 * * *` - 每 6 小时一次
- `0 0 * * 1` - 每周一凌晨
#### Vercel/Netlify 配置
这些平台也支持通过 webhook 设置定时构建:
```yaml
# 在内容仓库创建 .github/workflows/scheduled-build.yml
name: Scheduled Build
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Trigger Deploy
run: |
curl -X POST "${{ secrets.DEPLOY_HOOK_URL }}"
```
---
### 推荐配置组合
#### 最佳实践 (推荐)
结合多种方式,确保稳定性:
```yaml
# 代码仓库 .github/workflows/deploy.yml
on:
push:
branches:
- main
repository_dispatch: # 内容更新触发
types:
- content-updated
schedule: # 兜底方案
- cron: '0 2 * * *'
workflow_dispatch: # 手动触发
```
**优势**:
- ✅ 内容更新实时触发 (repository_dispatch)
- ✅ 每天自动同步,防止遗漏 (schedule)
- ✅ 支持手动触发调试 (workflow_dispatch)
---
### 验证配置
#### 检查清单
- [ ] 创建了 PAT Token 或 Deploy Hook
- [ ] 在内容仓库添加了对应的 Secret
- [ ] 创建了内容仓库的触发工作流
- [ ] 更新了代码仓库的部署工作流
- [ ] 测试了一次提交,确认触发成功
#### 测试步骤
1. **在内容仓库修改文章**:
```bash
cd /path/to/Mizuki-Content
# 编辑文章
git add .
git commit -m "test: trigger build"
git push
```
2. **查看内容仓库 Actions**:
- 访问 `https://github.com/your-username/Mizuki-Content/actions`
- 确认 "Trigger Build" 工作流运行成功
3. **查看代码仓库 Actions**:
- 访问 `https://github.com/your-username/Mizuki/actions`
- 确认部署工作流被触发
- 查看日志确认内容同步成功
4. **查看部署平台**:
- Vercel/Netlify/CF Pages: 查看部署历史
- GitHub Pages: 访问站点确认更新
---
### 故障排查
#### 问题 1: 内容仓库推送后没有触发构建
**检查**:
1. 内容仓库的 Actions 是否运行?
- 查看 Actions 页面,确认工作流被触发
2. PAT Token 权限是否正确?
- 需要 `repo` 完整权限
3. 代码仓库名称是否正确?
- 格式: `owner/repo`
**调试**:
```yaml
# 在内容仓库工作流中添加调试步骤
- name: Debug
run: |
echo "Repository: your-username/Mizuki"
echo "Event type: content-updated"
```
#### 问题 2: Repository dispatch 触发成功但构建失败
**检查**:
1. 代码仓库的 Actions 是否启用?
- Settings → Actions → General → 确保启用
2. 工作流文件是否包含 `repository_dispatch` 触发器?
3. 环境变量是否正确配置?
#### 问题 3: PAT Token 过期
**现象**: 工作流运行失败,提示认证错误
**解决**:
1. 重新生成 PAT Token
2. 更新内容仓库的 Secret
3. 测试触发
#### 问题 4: Deploy Hook 无效
**检查**:
1. Hook URL 是否正确复制?
2. Secret 是否正确添加?
3. 使用 curl 测试 Hook:
```bash
curl -X POST "https://api.vercel.com/v1/integrations/deploy/..."
```
---

271
docs/MIGRATION_GUIDE.md Normal file
View File

@@ -0,0 +1,271 @@
# Mizuki 内容迁移指南
本指南将帮助你将现有的 Mizuki 博客从单仓库模式迁移到代码内容分离模式。
> 💡 **提示**: 如果是新项目,建议先阅读 [内容分离完整指南](./CONTENT_SEPARATION.md)
## 📋 迁移前准备
### 检查清单
- [ ] **备份整个项目** (重要!)
- [ ] 确保所有更改已提交到 Git
- [ ] 了解你要使用的模式 (推荐 Submodule)
- [ ] 在 GitHub/GitLab 创建新的内容仓库
## 🚀 迁移步骤
### 步骤 1: 创建内容仓库
```bash
# 创建并进入新目录
mkdir Mizuki-Content
cd Mizuki-Content
# 初始化 Git 仓库
git init
# 创建目录结构
mkdir -p posts spec data images/albums images/diary images/posts
# 创建 README
cat > README.md << 'EOF'
# Mizuki 博客内容
这是 Mizuki 博客的内容仓库,包含所有文章、数据和图片。
## 目录结构
- `posts/` - 博客文章
- `spec/` - 特殊页面 (关于、友链等)
- `data/` - 数据文件 (番剧、项目、技能、时间线)
- `images/` - 图片资源
## 使用方法
此仓库作为 Mizuki 代码仓库的内容源,通过 Git Submodule 或独立模式关联。
详细说明请查看: https://github.com/matsuzaka-yuki/Mizuki
EOF
```
### 步骤 2: 从 Mizuki 项目复制内容
```bash
# 设置路径变量
MIZUKI_PATH="/path/to/your/Mizuki"
CONTENT_PATH="/path/to/Mizuki-Content"
# 复制文章
cp -r "$MIZUKI_PATH/src/content/posts/"* "$CONTENT_PATH/posts/"
# 复制特殊页面
cp -r "$MIZUKI_PATH/src/content/spec/"* "$CONTENT_PATH/spec/"
# 复制数据文件
cp "$MIZUKI_PATH/src/data/anime.ts" "$CONTENT_PATH/data/" 2>/dev/null || echo "anime.ts not found"
cp "$MIZUKI_PATH/src/data/projects.ts" "$CONTENT_PATH/data/" 2>/dev/null || echo "projects.ts not found"
cp "$MIZUKI_PATH/src/data/skills.ts" "$CONTENT_PATH/data/" 2>/dev/null || echo "skills.ts not found"
cp "$MIZUKI_PATH/src/data/timeline.ts" "$CONTENT_PATH/data/" 2>/dev/null || echo "timeline.ts not found"
# 复制图片
cp -r "$MIZUKI_PATH/public/images/albums/"* "$CONTENT_PATH/images/albums/" 2>/dev/null || echo "albums not found"
cp -r "$MIZUKI_PATH/public/images/diary/"* "$CONTENT_PATH/images/diary/" 2>/dev/null || echo "diary not found"
echo "✅ 内容复制完成!"
```
### 步骤 3: 提交内容仓库
```bash
cd "$CONTENT_PATH"
# 添加所有文件
git add .
# 提交
git commit -m "Initial commit: Migrate content from Mizuki monorepo"
# 添加远程仓库 (替换为你的仓库地址)
git remote add origin https://github.com/your-username/Mizuki-Content.git
# 推送
git branch -M master
git push -u origin master
echo "✅ 内容仓库已推送!"
```
### 步骤 4: 配置 Mizuki 代码仓库
```bash
cd "$MIZUKI_PATH"
# 创建 .env 文件
cp .env.example .env
# 编辑 .env 文件,启用内容分离
cat > .env << 'EOF'
# 启用内容分离
ENABLE_CONTENT_SYNC=true
# 内容仓库配置
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=true
EOF
# 运行同步脚本
pnpm run sync-content
# 提交更改
git add .env.example
git commit -m "Enable content separation"
git push
```
> 📖 更多配置选项请参考 [内容分离完整指南](./CONTENT_SEPARATION.md)
### 步骤 5: 清理原仓库中的内容 (可选)
⚠️ **警告**: 只有在确认内容已成功迁移后才执行此步骤!
```bash
cd "$MIZUKI_PATH"
# 备份原内容 (以防万一)
mkdir -p ../mizuki-content-backup
cp -r src/content/posts ../mizuki-content-backup/
cp -r src/content/spec ../mizuki-content-backup/
cp -r src/data ../mizuki-content-backup/
cp -r public/images ../mizuki-content-backup/
# 删除已迁移的内容 (保留目录结构)
rm -rf src/content/posts/*
rm -rf src/content/spec/*
rm -f src/data/anime.ts src/data/projects.ts src/data/skills.ts src/data/timeline.ts
rm -rf public/images/albums/* public/images/diary/*
# 创建 .gitkeep 文件保留目录
touch src/content/posts/.gitkeep
touch src/content/spec/.gitkeep
touch public/images/albums/.gitkeep
touch public/images/diary/.gitkeep
# 提交更改
git add .
git commit -m "Remove migrated content (now in separate repository)"
git push
```
## 🧪 测试迁移
### 本地测试
```bash
cd "$MIZUKI_PATH"
# 同步内容
pnpm run sync-content
# 启动开发服务器
pnpm dev
# 访问 http://localhost:4321 检查:
# - 文章是否正常显示
# - 图片是否正确加载
# - 特殊页面是否工作
# - 数据页面是否正常 (番剧、项目等)
```
### 构建测试
```bash
# 构建项目
pnpm build
# 预览构建结果
pnpm preview
# 检查所有功能是否正常
```
## 🔄 日常工作流
### 更新内容
```bash
# 1. 在内容仓库中修改
cd "$CONTENT_PATH"
# 编辑文件...
git add .
git commit -m "Update content"
git push
# 2. 在代码仓库中同步
cd "$MIZUKI_PATH"
pnpm run sync-content
```
### 使用 Submodule 时
```bash
cd "$MIZUKI_PATH"
# 更新 submodule 到最新版本
git submodule update --remote --merge
# 或者使用同步脚本 (推荐)
pnpm run sync-content
# 提交 submodule 更新
git add content
git commit -m "Update content submodule"
git push
```
## 🚀 部署配置
迁移完成后,需要在部署平台配置环境变量:
```bash
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
USE_SUBMODULE=true
```
详细的部署配置(包括私有仓库、GitHub Actions、Vercel 等)请参考 [内容分离完整指南 - CI/CD 部署](./CONTENT_SEPARATION.md#-cicd-部署)
## ⚠️ 常见问题
### Q: 同步脚本失败怎么办?
A: 检查:
1. 网络连接是否正常
2. Git 凭据是否配置正确
3. `ENABLE_CONTENT_SYNC=true` 是否已设置
4. `CONTENT_REPO_URL` 是否正确
5. 是否有足够的磁盘空间
运行 `pnpm run check-env` 检查配置。
### Q: 符号链接在 Windows 上不工作?
A: 需要以管理员身份运行,或者脚本会自动切换到复制模式。
### Q: 如何回滚到单仓库模式?
A: 在 `.env` 中设置 `ENABLE_CONTENT_SYNC=false`,然后从备份或内容仓库复制内容回本地。
### Q: 遇到私有仓库认证问题?
A: 参考 [内容分离完整指南 - 私有仓库配置](./CONTENT_SEPARATION.md#-私有仓库配置)
## 📚 参考文档
- [内容分离完整指南](./CONTENT_SEPARATION.md) - 详细配置说明
- [内容仓库结构说明](./CONTENT_REPOSITORY.md) - 推荐的仓库结构
- [Git Submodule 文档](https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97)
---
💡 **提示**: 迁移前建议先在测试环境中验证整个流程!

110
docs/README.md Normal file
View File

@@ -0,0 +1,110 @@
# Mizuki 文档索引
欢迎查阅 Mizuki 的详细文档!
## 📚 文档列表
### 核心文档
- **[../README.zh.md](../README.zh.md)** - 项目主文档 (简体中文)
- 快速开始
- 功能特性
- 基础配置
- 常见问题
### 多语言文档
- **[../README.md](../README.md)** - English
- **[../README.ja.md](../README.ja.md)** - 日本語
- **[../README.tw.md](../README.tw.md)** - 繁體中文
### 内容分离相关
- **[CONTENT_SEPARATION.md](./CONTENT_SEPARATION.md)** - 内容分离完整指南 ⭐
- ENABLE_CONTENT_SYNC 控制开关
- 环境变量配置详解
- 私有仓库配置方法
- 模式切换指南
- 故障排查
- **[CONTENT_REPOSITORY.md](./CONTENT_REPOSITORY.md)** - 内容仓库结构指南
- 推荐的目录结构
- 文件组织方式
- 内容编写规范
- 图片管理建议
- **[MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md)** - 内容迁移指南
- 从单仓库迁移到分离模式
- 详细迁移步骤
- 测试验证方法
### 部署相关
- **[DEPLOYMENT.md](./DEPLOYMENT.md)** - 部署完整指南 ⭐
- 各平台部署配置 (GitHub Pages / Vercel / Netlify / Cloudflare Pages)
- 内容仓库更新自动触发构建
- 私有仓库认证
- 故障排查
- **[AUTO_BUILD_TRIGGER.md](./AUTO_BUILD_TRIGGER.md)** - 自动构建触发快速参考 🆕
- 5 步快速配置,解决内容更新不触发部署的问题
## 🚀 快速查找
### 我是新手,想快速开始
→ 阅读 [主 README](../README.zh.md)
### 我想部署博客
→ 阅读 [部署指南](./DEPLOYMENT.md)
### 我想使用内容分离功能
→ 阅读 [内容分离完整指南](./CONTENT_SEPARATION.md)
### 我想从单仓库迁移到分离模式
→ 阅读 [内容迁移指南](./MIGRATION_GUIDE.md)
### 我想配置私有内容仓库
→ 阅读 [内容分离指南 - 私有仓库配置](./CONTENT_SEPARATION.md#-私有仓库配置)
### 我的部署遇到问题
→ 阅读 [部署指南 - 故障排查](./DEPLOYMENT.md#-故障排查)
### 我遇到了内容同步错误
→ 阅读 [内容分离指南 - 故障排查](./CONTENT_SEPARATION.md#-故障排查)
### 内容仓库更新后站点没有自动重新部署 🆕
→ 阅读 [自动构建触发快速参考](./AUTO_BUILD_TRIGGER.md)
## 📖 文档架构
```
docs/
├── README.md # 本文档 - 索引导航
├── CONTENT_SEPARATION.md # 内容分离核心指南
├── CONTENT_REPOSITORY.md # 内容仓库结构
├── MIGRATION_GUIDE.md # 迁移指南
├── DEPLOYMENT.md # 部署完整指南
├── AUTO_BUILD_TRIGGER.md # 自动构建触发快速参考
└── image/ # 文档图片资源
```
## 🎯 文档使用建议
### 新用户推荐阅读顺序
1. [主 README](../README.zh.md) - 了解项目基本情况
2. [部署指南](./DEPLOYMENT.md) - 选择平台并部署
3. (可选) [内容分离指南](./CONTENT_SEPARATION.md) - 高级功能
### 高级用户推荐
- 直接查阅具体主题的文档
- 使用快速查找定位问题解决方案
## 🤝 需要帮助?
- 查看 [GitHub Issues](https://github.com/matsuzaka-yuki/Mizuki/issues)
- 阅读相关文档的故障排查章节
- 运行 `pnpm run check-env` 检查配置
祝你使用愉快!🎉

BIN
docs/image/1.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
docs/image/2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
docs/image/3.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
docs/image/4.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/image/5.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
docs/image/6.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

92
package.json Normal file
View File

@@ -0,0 +1,92 @@
{
"name": "mizuki",
"type": "module",
"version": "7.6.0",
"scripts": {
"sync-content": "node scripts/sync-content.js",
"init-content": "node scripts/init-content-repo.js",
"predev": "node scripts/sync-content.js || true",
"prebuild": "node scripts/sync-content.js || true",
"dev": "astro dev",
"start": "astro dev",
"check": "astro check",
"build": "astro build && pagefind --site dist && node scripts/compress-fonts.js",
"preview": "astro preview",
"astro": "astro",
"type-check": "tsc --noEmit --isolatedDeclarations",
"new-post": "node scripts/new-post.js",
"format": "biome format --write ./src",
"lint": "biome check --write ./src",
"preinstall": "npx only-allow pnpm",
"compress-fonts": "node scripts/compress-fonts.js",
"test-font-compression": "node scripts/test-font-compression.js"
},
"dependencies": {
"@astrojs/check": "^0.9.6",
"@astrojs/rss": "^4.0.14",
"@astrojs/sitemap": "^3.6.0",
"@astrojs/svelte": "7.2.2",
"@astrojs/tailwind": "^6.0.2",
"@expressive-code/core": "^0.41.3",
"@expressive-code/plugin-collapsible-sections": "^0.41.3",
"@expressive-code/plugin-line-numbers": "^0.41.3",
"@fancyapps/ui": "^6.1.6",
"@fontsource-variable/jetbrains-mono": "^5.2.8",
"@fontsource/roboto": "^5.2.9",
"@iconify-json/fa6-brands": "^1.2.6",
"@iconify-json/fa6-regular": "^1.2.4",
"@iconify-json/fa6-solid": "^1.2.4",
"@iconify-json/material-symbols": "^1.2.48",
"@iconify-json/simple-icons": "^1.2.60",
"@iconify/svelte": "^4.2.0",
"@swup/astro": "^1.7.0",
"@tailwindcss/typography": "^0.5.19",
"astro": "5.16.2",
"astro-expressive-code": "^0.41.3",
"astro-icon": "^1.1.5",
"bcryptjs": "^3.0.3",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.19",
"hastscript": "^9.0.1",
"katex": "^0.16.25",
"markdown-it": "^14.1.0",
"marked": "^16.4.2",
"mdast-util-to-string": "^4.0.0",
"node-html-parser": "^7.0.1",
"overlayscrollbars": "^2.12.0",
"pagefind": "^1.4.0",
"photoswipe": "^5.4.4",
"reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-components": "^0.3.0",
"rehype-katex": "^7.0.1",
"rehype-slug": "^6.0.0",
"remark-directive": "^3.0.1",
"remark-directive-rehype": "^0.4.2",
"remark-github-admonitions-to-directives": "^1.0.5",
"remark-math": "^6.0.0",
"remark-sectionize": "^2.1.0",
"sanitize-html": "^2.17.0",
"satori": "^0.18.3",
"sharp": "^0.34.5",
"stylus": "^0.64.0",
"svelte": "^5.43.14",
"tailwindcss": "^3.4.18",
"typescript": "^5.9.3",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@astrojs/ts-plugin": "^1.10.6",
"@biomejs/biome": "2.3.8",
"@iconify-json/mdi": "^1.2.3",
"@rollup/plugin-yaml": "^4.1.2",
"@types/hast": "^3.0.4",
"@types/markdown-it": "^14.1.2",
"@types/mdast": "^4.0.4",
"@types/sanitize-html": "^2.16.0",
"fontmin": "^1.1.1",
"postcss-import": "^16.1.1",
"postcss-nesting": "^13.0.2"
},
"packageManager": "pnpm@10.22.0"
}

6
pagefind.yml Normal file
View File

@@ -0,0 +1,6 @@
exclude_selectors:
- "span.katex"
- "span.katex-display"
- "[data-pagefind-ignore]"
- ".search-panel"
- "#search-panel"

12715
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

6
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,6 @@
onlyBuiltDependencies:
- '@parcel/watcher'
- esbuild
- sharp
- swup
- ttf2woff2

11
postcss.config.mjs Normal file
View File

@@ -0,0 +1,11 @@
import postcssImport from "postcss-import";
import tailwindcss from "tailwindcss";
import postcssNesting from "tailwindcss/nesting/index.js";
export default {
plugins: {
"postcss-import": postcssImport, // to combine multiple css files
"tailwindcss/nesting": postcssNesting,
tailwindcss: tailwindcss,
},
};

9
public/_headers Normal file
View File

@@ -0,0 +1,9 @@
/atom.xml
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 86400
/rss.xml
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 86400

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,94 @@
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
} /*!
Theme: GitHub Dark
Description: Dark theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/
.hljs {
color: #c9d1d9;
background: #0d1117;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #ff7b72;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #d2a8ff;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-variable {
color: #79c0ff;
}
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #a5d6ff;
}
.hljs-built_in,
.hljs-symbol {
color: #ffa657;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: #8b949e;
}
.hljs-name,
.hljs-quote,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #7ee787;
}
.hljs-subst {
color: #c9d1d9;
}
.hljs-section {
color: #1f6feb;
font-weight: 700;
}
.hljs-bullet {
color: #f2cc60;
}
.hljs-emphasis {
color: #c9d1d9;
font-style: italic;
}
.hljs-strong {
color: #c9d1d9;
font-weight: 700;
}
.hljs-addition {
color: #aff5b4;
background-color: #033a16;
}
.hljs-deletion {
color: #ffdcd7;
background-color: #67060c;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/assets/home/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
public/assets/home/site.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

1225
public/assets/js/bcrypt.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

6811
public/assets/js/crypto-js.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

8422
public/assets/js/highlight.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

2236
public/assets/js/marked.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

2
public/assets/js/twikoo.all.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
[
{
"id": 1,
"title": "下完这场雨",
"artist": "后弦",
"cover": "assets/music/cover/1.jpg",
"url": "assets/music/url/xwzcy.mp3",
"duration": 260
},
{
"id": 2,
"title": "紧急联络人",
"artist": "Gareth.T",
"cover": "assets/music/cover/2.jpg",
"url": "assets/music/url/jjllr.mp3",
"duration": 205
},
{
"id": 3,
"title": "寂寞寂寞不好",
"artist": "曹格",
"cover": "assets/music/cover/3.jpg",
"url": "assets/music/url/jmjmbh.mp3",
"duration": 242
},
{
"id": 4,
"title": "习惯失恋",
"artist": "容祖儿",
"cover": "assets/music/cover/4.jpg",
"url": "assets/music/url/xgsl.mp3",
"duration": 236
},
{
"id": 5,
"title": "想你的夜",
"artist": "关喆",
"cover": "assets/music/cover/5.jpg",
"url": "assets/music/url/xndy.mp3",
"duration": 256
},
{
"id": 6,
"title": "用背脊唱情歌",
"artist": "Gareth.T",
"cover": "assets/music/cover/6.jpg",
"url": "assets/music/url/ybjcqg.mp3",
"duration": 210
},
{
"id": 7,
"title": "不该",
"artist": "周杰伦 张惠妹",
"cover": "assets/music/cover/7.jpg",
"url": "assets/music/url/bg.mp3",
"duration": 270
}
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
public/favicon/site.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

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

Some files were not shown because too many files have changed in this diff Show More