9.1 KiB
9.1 KiB
个人主页 — 需求文档
1. 项目范围
本项目是一个公开静态站点 + 构建时数据同步层。
站点运行时仍然是纯静态页面,但在构建阶段由本项目主动向 Gitea / Seafile 拉取所需数据,清洗后生成本地只读数据文件,再交给 Astro 渲染。
也就是说:
- 运行时:纯静态站点,对外公开访问
- 构建时:服务端脚本拉取远程数据、生成内容文件
AstrBot、定时任务、手动脚本等都可以作为“触发构建”的外部入口,但同步逻辑本身属于这个仓库的一部分。
- 域名:
sepcomet.xyz(备案中) - 部署:自有服务器 Docker 环境
- 访问:完全公开,求职时可直接给链接
- 用户背景:Unity 客户端开发,Web 经验不多,怎么方便怎么来
2. 页面与功能
2.1 首页
- Hero 区:头像、名字、一句话简介、社交链接(GitHub/Gitea/Blog 等)
- 开发日志摘要:最新 3-5 条日志的卡片列表
- 精选项目:featured 项目的卡片展示
- Gitea 活动概览:贡献热力图(可选)
2.2 开发日志(/logs)
- 按时间倒序的日志列表
- 每条日志卡片:标题、日期、标签、摘要
- 点击进入日志详情页(/logs/[slug])
- 日志详情:Markdown 全文渲染,关联的仓库名和 commit 链接
- 内容来自
src/content/logs/下的.md文件 - 首版允许日志继续由手动维护或外部系统写入;日志生成逻辑不要求在本项目内实现
2.3 项目展示(/projects)
- 项目卡片网格布局
- 每个项目卡片:名称、描述、封面图、标签
- 点击可展开/跳转详情:演示视频(如有)、Gitea 仓库链接、Seafile 下载链接(如有)
- 数据来源:构建时从 Gitea / Seafile 拉取并生成的结构化数据文件
- 页面层只读取最终生成数据,不直接处理上游 API 响应
2.4 Gitea 统计(可嵌入首页或独立页)
- 贡献热力图
- 最近活动列表
- 仓库简要信息(名称、描述、更新时间、链接等)
- 数据由构建脚本从 Gitea 拉取并清洗
- 运行时不依赖浏览器直接访问带 token 的私有 API
2.5 Seafile 分享(/shares 或首页侧栏)
- 文件分享链接列表,每条含:文件名、描述、链接、时间
- 数据来源:构建时从 Seafile 拉取并生成的结构化数据文件
- 支持展示特定目录或特定文件(如项目打包产物)
- 首版优先展示文件元数据与下载链接;如确有需要,可在后续增加“构建时镜像文件到站点静态目录”的能力
3. 功能优先级
P0(必须有):
- 首页 Hero 区(个人简介 + 链接)
- 日志列表 + 详情页(Markdown 渲染)
- 项目展示卡片
- 构建时 Gitea / Seafile 数据同步入口
P1(很重要):
- Gitea 贡献热力图(基于构建期抓取的数据渲染)
- 仓库摘要信息同步
- Seafile 分享列表同步
- 响应式布局
P2(锦上添花):
- 日志按标签/时间筛选
- 项目演示视频嵌入
- 构建时镜像特定 Seafile 文件到站点静态目录
- 深色模式
4. 技术选型
| 层 | 选型 | 理由 |
|---|---|---|
| 框架 | Astro | 静态站点生成,原生 .md 支持,零 JS 默认 + 可选交互岛 |
| 样式 | CSS(当前) / Tailwind CSS(可选) | 首版以简单直接、低心智负担为主,是否接 Tailwind 以后续实现成本决定 |
| 交互组件 | Astro 原生 + 按需引入 React | 默认静态渲染;只有热力图等确需交互时再引入前端组件 |
| 内容存储 | 文件系统(.md + .json) |
构建脚本先把远程数据清洗为本地文件,再统一消费 |
| 数据同步 | Node.js 构建脚本 | 服务端拉取 Gitea / Seafile 数据,避免浏览器暴露 token |
| 部署 | Nginx + Docker | 静态文件服务,单容器 |
| 构建触发 | 手动 / 定时任务 / AstrBot | npm run content:sync → npm run build → 部署静态产物 |
5. 数据模型
日志 frontmatter(src/content/logs/*.md)
---
title: "personal-homepage 项目初始化"
date: 2026-05-03
repo: "sepcomet/personal-homepage"
tags: [astro, init, setup]
summary: "搭建 Astro 项目骨架,确定目录结构与部署方案"
---
正文内容(Markdown) — 客观 diff 分析 + 主观动机,由 AstrBot 生成后写入
项目数据(示例:src/data/generated/projects.json)
[
{
"name": "personal-homepage",
"description": "个人主页 Dashboard",
"gitea_repo": "sepcomet/personal-homepage",
"repo_url": "https://gitea.sepcomet.xyz/sepcomet/personal-homepage",
"cover_image": "/images/projects/homepage.png",
"demo_video": "https://...",
"download_link": "https://seafile.sepcomet.xyz/...",
"tags": ["astro", "web"],
"featured": true,
"updated_at": "2026-05-05T00:00:00Z",
"source": "gitea+seafile"
}
]
Gitea 活动数据(示例:src/data/generated/gitea-activity.json)
{
"updatedAt": "2026-05-05T00:00:00Z",
"days": [
{ "date": "2026-05-01", "count": 3 },
{ "date": "2026-05-02", "count": 0 }
],
"recent": [
{
"type": "push",
"repo": "sepcomet/personal-homepage",
"message": "更新首页模块结构",
"url": "https://gitea.sepcomet.xyz/...",
"time": "2026-05-05T00:00:00Z"
}
]
}
分享 / 下载数据(示例:src/data/generated/shares.json)
[
{
"name": "personal-homepage-demo.zip",
"description": "项目打包产物",
"url": "https://seafile.sepcomet.xyz/...",
"time": "2026-05-05T00:00:00Z",
"size": 12345678,
"source": "seafile"
}
]
站点配置(src/config.ts)
export const site = {
name: "SepComet",
title: "个人主页",
tagline: "Unity 开发者",
avatar: "/images/avatar.png",
gitea: {
url: "https://gitea.sepcomet.xyz",
username: "sepcomet"
},
links: [
{ name: "Gitea", url: "https://gitea.sepcomet.xyz" },
{ name: "GitHub", url: "https://github.com/sepcomet" }
]
}
6. 目录结构
personal-homepage/
├── src/
│ ├── pages/
│ │ ├── index.astro # 首页
│ │ ├── logs/
│ │ │ ├── index.astro # 日志列表
│ │ │ └── [slug].astro # 日志详情
│ │ ├── projects/
│ │ │ └── index.astro # 项目展示
│ │ └── shares.astro # Seafile 分享
│ ├── components/
│ │ ├── Header.astro
│ │ ├── Footer.astro
│ │ ├── Hero.astro
│ │ ├── LogCard.astro
│ │ ├── ProjectCard.astro
│ │ └── GiteaHeatmap.jsx # React Island
│ ├── content/
│ │ └── logs/ # *.md 日志内容
│ ├── data/
│ │ └── generated/ # 构建时同步生成的 JSON
│ │ ├── gitea-activity.json
│ │ ├── projects.json
│ │ └── shares.json
│ ├── config.ts
│ └── styles/
│ └── global.css
├── scripts/
│ ├── fetch-gitea.ts
│ ├── fetch-seafile.ts
│ └── sync-content.ts
├── public/
│ ├── images/
│ │ └── avatar.png
│ └── downloads/ # 可选:构建时镜像的下载文件
│ └── favicon.svg
├── astro.config.mjs
├── Dockerfile
├── docker-compose.yml
└── package.json
7. 部署
# docker-compose.yml
services:
homepage:
build: .
ports:
- "8080:80"
volumes:
- ./src/content:/app/src/content # 日志/项目内容热更新
- ./public/images:/app/public/images
restart: unless-stopped
- Docker 构建阶段:
npm run build生成静态文件 - Docker 构建阶段:先执行
npm run content:sync,再执行npm run build - 运行阶段:Nginx 托管
dist/目录 - 日常更新:定时任务 / AstrBot 触发同步与重建
- Gitea / Seafile token 只存在于构建环境,不进入前端产物
8. 实施计划
| Phase | 内容 | 产出 |
|---|---|---|
| 1 | Astro 项目初始化 + 首页/日志/项目/分享骨架 | 可访问的骨架页面 |
| 2 | 日志系统:列表页 + 详情页 + frontmatter 解析 + 示例内容 | 日志模块 |
| 3 | 数据同步层:Gitea / Seafile 拉取脚本、环境变量、生成文件 | 构建期数据链路 |
| 4 | 页面改读生成数据 + Gitea 活动真实化 + 仓库摘要接入 | 统计与项目模块 |
| 5 | Docker、定时重建、响应式打磨、深色模式、SEO | 收尾 |
9. 不在此项目范围内
- AstrBot 插件开发(独立项目)
- 日志 markdown 文件的生成逻辑(可由 AstrBot 或其他系统负责)
- 自动化部署流程(CI/CD,可后续补充)
本项目负责:构建时拉取远程数据 / 读取本地日志 → 生成站点数据文件 → 渲染为 HTML → 静态托管。