基于 Astro 的个人博客项目。
日常操作看 docs/operations.md,变更记录看 CHANGELOG.md,仓库外的配置变更(Vercel / DNS 等)记在 docs/ops-log.md。
/log 会在构建时读取公开 Telegram 频道,生成时间线。频道用户名在
src/site.config.ts 的 telegramLog.channel 中配置;设为空字符串即可关闭这个功能。
页面默认 limit: 0,保留整个公开频道历史,不存在固定的 60 条上限。图片会下载到
public/log-media/,构建产物只保留本地化后的 webp。
频道变更由 .github/workflows/telegram-log.yml 每小时检查一次,也可以在 GitHub Actions
中手动运行。检查会比较上次构建写入的 /log/latest.json 指纹;保留范围内的新增、删除和
编辑都会触发对应站点重建。多图消息在时间线上显示为一张铺满预览框的缩略图,点击后用
全屏查看器浏览原比例图片和同组媒体。完整配置、部署钩子和故障处理见
Telegram 插件文档 与 操作指南。
图源是 docs/architecture/diagram.html——一个自包含的深色架构图(内联 SVG、手工排版、坐标固定),按 Cocoon 架构图 skill 的风格绘制。当前图对应 v2.1 的 registry-driven 架构:site.config.ts 装配 block,skins/ 与 arrangements/ 分别提供视觉 token 和列表规则,i18n 字典以共享 hash module 下发,正文图片统一走 src/assets 的 Astro 图片管线。改完图后重新生成 .png:用浏览器打开该 HTML,点右上角 ⋯ → 🖼️ PNG 导出即可,无需额外工具。
.
├── docs/
│ ├── architecture/ # 架构图:.html 源(自带导出)+ .png
│ ├── operations.md # 操作指南:发文、换封面、改外观、加组件
│ └── ops-log.md # 运维日志:仓库外的配置变更(Vercel / DNS 等)
├── .github/workflows/
│ └── telegram-log.yml # 定时检查频道并触发站点重建
├── plugins/telegram-log/ # Telegram 日常页的数据加载、媒体本地化和展示
├── public/ # 直接静态资源(按 URL 原样输出,不经过构建管线)
│ ├── avatars/ # 构建时下载并本地化的友链头像
│ ├── fonts/
│ ├── music/ # 播放器音频
│ └── vendor/ # 第三方脚本(如 Waline)
├── scripts/ # 发布与内容维护脚本
├── src/
│ ├── arrangements/ # 文章列表的 5 种排版,各一个 css + 一份登记表
│ ├── assets/ # 走 Astro 图片管线的资源
│ │ ├── banner/ # 首屏背景图
│ │ ├── blog/<slug>/ # 文章正文配图
│ │ └── covers/ # 文章封面池
│ ├── blocks/ # 组件库,按接口形状分目录,见 docs/operations.md
│ │ ├── behavior/ # 脚本/行为,无独立可见 UI,挂一次全局生效
│ │ ├── chrome/ # Header / Footer / 阅读设置面板
│ │ ├── decor/ # 背景、进度条、返回顶部
│ │ ├── surface/ # 带 slot 的容器
│ │ ├── view/ # 需要页面喂数据的展示组件
│ │ ├── widget/ # 侧栏挂件,自己查数据
│ │ └── registry.ts # 能被区域放置的 block 登记表
│ ├── components/ # 不属于 block 体系的:BaseHead、SearchModal、Region
│ ├── content/
│ │ └── blog/ # 博客 Markdown/MDX
│ ├── data/ # 站点数据(友链、播放列表、阅读设置项)
│ ├── i18n/
│ ├── layouts/ # 页面骨架(BaseLayout / BlogPost / PolicyPage)
│ ├── pages/
│ │ ├── api/ # search.json 等端点
│ │ ├── posts/ # 列表 / 归档 / 分页 / 详情
│ │ └── terms/ # 隐私、版权、免责声明等
│ ├── skins/ # 两套皮肤的 token,各一个 tokens.css + 一份登记表
│ ├── styles/ # global.css,只消费 token 不定义 token
│ ├── types/
│ ├── utils/
│ ├── consts.ts
│ ├── content.config.ts
│ ├── env.d.ts # inline script 挂在 window 上的全局声明
│ └── site.config.ts # 装配文件:站点由哪些 block 组成、默认皮肤与排版
├── astro.config.mjs
├── CHANGELOG.md # 可感知的变化与架构调整
└── package.json
这里的“插件式”指构建期的 registry + slots 装配,不是运行时安装 npm 插件:Region 按
BlockName 从 BLOCKS 解析组件,site.config.ts 的 regions 保存 placement(名称、props、
skins)。三层的分工是:blocks/ 只有功能实现,skins/ 只有取值,arrangements/ 只有排版规则;
site.config.ts 负责装配。加皮肤或加排版都是两步(写文件 + 登记一行),细节见
docs/operations.md。
构建时,Astro 从 src/content/blog/ 读取 Markdown/MDX,生成文章页、归档、标签、系列、RSS、站点地图和搜索索引;友链 RSS 在构建时整理为 /friend-circle.json,头像下载到 public/avatars/。正文插图和封面留在 src/assets/,由 Astro 处理成带 hash 的 webp;public/ 只放必须按原 URL 输出的字体、音频、头像和第三方脚本。浏览器端只负责主题、语言、阅读设置、搜索、评论和图片灯箱等交互。
- 新文章放在
src/content/blog/。 - 文章 frontmatter 默认
heroImage使用src/assets/cover.svg。 - 可以通过 frontmatter 的
hidden: true暂时隐藏文章(不会出现在列表、归档、标签、RSS、搜索,也不会生成公开详情页)。 - 文章插图放在
src/assets/blog/<文章-slug>/,封面放src/assets/covers/,首屏背景放src/assets/banner/。在 Markdown 用相对路径引用,如。放这里才会过 Astro 的图片管线(转 webp、加 hash);放public/会原样输出,等于多发一份没人引用的原图。 - 需要固定公网 URL、且不该被改写的资源(字体、音频、第三方脚本)才放
public/。
需要 Node 22(Astro 7 在 Node 20 上直接拒绝启动)。仓库里有 .nvmrc,进目录 nvm use 即可。
npm run dev:本地开发npm run build:生产构建npm run preview:本地预览构建产物npm run test:运行测试(含皮肤与排版的契约检查)npx astro check:类型检查,应为 0 errornpm run new:创建新文章模板npm run covers:抓取新的封面候选图npm run covers:lock:给还没有封面的文章各分配一张npm run watch:frontmatter:自动补齐 frontmatter
现在有两种方式:
npm run new/npm run new:post:创建新文章并自动写入完整 frontmatternpm run watch:frontmatter:监听src/content/blog/,给“缺失 frontmatter 的 md/mdx”自动补齐
交互式创建(推荐):
npm run new命令行参数创建:
npm run new -- --title "我的新文章" --tags "astro,blog" --category "开发" --series "折腾记录"常用参数:
--title文章标题(必填)--slug文件名(默认由标题自动生成)--desc描述--tags逗号分隔标签--category分类--series系列--pinned是否置顶(true/false)--hidden是否隐藏(true/false)--hero头图路径(默认../../assets/cover.svg)--pubDate发布时间(默认当前时间)--dry-run只预览,不落盘
npm run watch:frontmatter说明:
- 启动后会先扫描一次
src/content/blog/ - 之后监听文件变化,发现没有 frontmatter 的
.md/.mdx会自动补齐 - 已经有 frontmatter 的文件不会被覆盖
在博客 Markdown 中支持以下写法,最终渲染为响应式 iframe:
@[video](https://www.youtube.com/watch?v=M7lc1UVf-VE)
@[youtube](M7lc1UVf-VE)
@[bilibili](https://www.bilibili.com/video/BV1xx411c7mD)本项目的架构图采用 Cocoon AI 开源的 Architecture Diagram Skill 绘制——其深色主题设计系统与内联 SVG 模板(MIT License,Copyright © 2025 Cocoon AI)为本图的样式与排版提供了基础。在此向原作者表示诚挚的谢意。
