338 lines
10 KiB
Markdown
338 lines
10 KiB
Markdown
|
|
# Next.js 个人博客系统
|
|||
|
|
|
|||
|
|
`Next.js` `博客` `TypeScript` `Tailwind CSS` `全栈`
|
|||
|
|
|
|||
|
|
# fuxiaochen
|
|||
|
|
|
|||
|
|
基于 Next.js 16.1 (App Router) 构建的高性能个人博客,采用 Chen Serif 设计系统(Variant-driven Design 方案)。
|
|||
|
|
|
|||
|
|
**本项目是一个个人学习技术和探索的项目,随时可能有 breaking change。不建议!!!不建议 !!!不建议 !!!用于生产环境,欢迎一起互相交流学习~**
|
|||
|
|
|
|||
|
|
## 功能特性
|
|||
|
|
|
|||
|
|
### 前台功能
|
|||
|
|
|
|||
|
|
- **首页**:大胆风格设计,液态渐变背景
|
|||
|
|
- **博客展示**:文章列表、分类浏览、标签筛选
|
|||
|
|
- **关于页面**:个人介绍、技能展示
|
|||
|
|
- **更新日志**:时间线风格版本历史
|
|||
|
|
- **登录页面**:液态风格设计
|
|||
|
|
- **SEO 优化**:Sitemap、OpenGraph 支持
|
|||
|
|
|
|||
|
|
### 后台管理
|
|||
|
|
|
|||
|
|
- **仪表盘**:数据概览
|
|||
|
|
- **博客管理**:CRUD 操作、Markdown 编辑(ByteMD)
|
|||
|
|
- **分类管理**:分类创建与维护
|
|||
|
|
- **标签管理**:标签管理
|
|||
|
|
- **用户管理**:用户信息维护、角色分配
|
|||
|
|
- **更新日志**:版本记录管理
|
|||
|
|
- **图片上传**:OSS 云存储集成
|
|||
|
|
- **UI 预览**:组件预览页面
|
|||
|
|
|
|||
|
|
### 技术亮点
|
|||
|
|
|
|||
|
|
- **Chen Serif 设计系统**:Variant-driven Design 变体驱动方案
|
|||
|
|
- **Server Actions**:接口优先设计模式
|
|||
|
|
- **Store 架构**:Interface-First 数据流
|
|||
|
|
- **权限管理**:基于角色的访问控制
|
|||
|
|
- **类型安全**:TypeScript + Zod 验证
|
|||
|
|
- **现代 UI**:Radix UI + Tailwind CSS 4
|
|||
|
|
|
|||
|
|
## 技术栈
|
|||
|
|
|
|||
|
|
| 类别 | 技术 |
|
|||
|
|
| -------- | -------------------------------------- |
|
|||
|
|
| 框架 | Next.js 16.1.1 (React 19.2.3) |
|
|||
|
|
| 数据库 | MySQL/MariaDB (Prisma ORM) |
|
|||
|
|
| 样式 | Tailwind CSS 4, Radix UI, Lucide React |
|
|||
|
|
| 编辑器 | ByteMD (Markdown) |
|
|||
|
|
| 状态管理 | SWR |
|
|||
|
|
| 表单 | React Hook Form + Zod |
|
|||
|
|
| 认证 | Better Auth(GitHub OAuth + 邮箱密码) |
|
|||
|
|
| 包管理器 | pnpm |
|
|||
|
|
| 部署 | PM2, Docker |
|
|||
|
|
|
|||
|
|
## 快速开始
|
|||
|
|
|
|||
|
|
### 环境要求
|
|||
|
|
|
|||
|
|
- Node.js >= 20
|
|||
|
|
- MySQL/MariaDB 8.0+
|
|||
|
|
- pnpm 9.x
|
|||
|
|
|
|||
|
|
### 安装依赖
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pnpm install
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 环境配置
|
|||
|
|
|
|||
|
|
参考 `.env.example` 文件配置环境变量。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cp .env.example .env
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```shell
|
|||
|
|
# Database 必须配置
|
|||
|
|
DATABASE_HOST="localhost"
|
|||
|
|
DATABASE_PORT="3306"
|
|||
|
|
DATABASE_USER="root"
|
|||
|
|
DATABASE_PASSWORD="your_password"
|
|||
|
|
DATABASE_NAME="fuxiaochen_dev"
|
|||
|
|
DATABASE_URL="mysql://root:your_password@localhost:3306/fuxiaochen_dev"
|
|||
|
|
|
|||
|
|
# Better Auth 必须配置
|
|||
|
|
GITHUB_CLIENT_ID="your_github_client_id"
|
|||
|
|
GITHUB_CLIENT_SECRET="your_github_client_secret"
|
|||
|
|
BETTER_AUTH_SECRET="your_better_auth_secret"
|
|||
|
|
BETTER_AUTH_URL="http://localhost:3000"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 数据库初始化
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 生成 Prisma Client
|
|||
|
|
pnpm db:gen
|
|||
|
|
|
|||
|
|
# 2. 推送 schema 变更到数据库
|
|||
|
|
pnpm db:push
|
|||
|
|
|
|||
|
|
# 3. 填充种子数据(可选)
|
|||
|
|
pnpm db:seed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 启动开发服务器
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pnpm dev
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
访问 http://localhost:3000
|
|||
|
|
|
|||
|
|
## 开发命令
|
|||
|
|
|
|||
|
|
| 命令 | 说明 |
|
|||
|
|
| ---------------- | --------------------- |
|
|||
|
|
| `pnpm dev` | 启动开发服务器 |
|
|||
|
|
| `pnpm build` | 构建生产版本 |
|
|||
|
|
| `pnpm start` | 启动生产服务器 |
|
|||
|
|
| `pnpm lint` | ESLint 检查 |
|
|||
|
|
| `pnpm lint:fix` | ESLint 检查并自动修复 |
|
|||
|
|
| `pnpm format` | Prettier 格式化代码 |
|
|||
|
|
| `pnpm db:gen` | 生成 Prisma Client |
|
|||
|
|
| `pnpm db:push` | 推送 schema 变更 |
|
|||
|
|
| `pnpm db:studio` | 打开 Prisma Studio |
|
|||
|
|
| `pnpm db:seed` | 填充种子数据 |
|
|||
|
|
| `pnpm pm2:start` | PM2 启动应用 |
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
fuxiaochen/
|
|||
|
|
├── app/ # Next.js App Router
|
|||
|
|
│ ├── (site)/ # 前台页面组
|
|||
|
|
│ │ ├── blog/ # 博客相关
|
|||
|
|
│ │ ├── about/ # 关于页面
|
|||
|
|
│ │ ├── changelog/ # 更新日志
|
|||
|
|
│ │ ├── login/ # 登录页面
|
|||
|
|
│ │ └── ui-preview/ # UI 组件预览
|
|||
|
|
│ ├── (admin)/ # 后台管理组
|
|||
|
|
│ │ ├── admin/ # 管理功能
|
|||
|
|
│ │ │ ├── blogs/ # 博客管理
|
|||
|
|
│ │ │ ├── categories/ # 分类管理
|
|||
|
|
│ │ │ ├── tags/ # 标签管理
|
|||
|
|
│ │ │ ├── users/ # 用户管理
|
|||
|
|
│ │ │ └── changelogs/ # 更新日志管理
|
|||
|
|
│ ├── actions/ # Server Actions
|
|||
|
|
│ └── api/ # API 路由
|
|||
|
|
├── components/ # 组件库
|
|||
|
|
│ ├── ui/ # 基础 UI 组件(Chen Serif 设计系统)
|
|||
|
|
│ ├── admin/ # 后台业务组件
|
|||
|
|
│ ├── blog/ # 博客业务组件
|
|||
|
|
│ └── layout/ # 布局组件(header, footer)
|
|||
|
|
├── stores/ # Store 实现 (Interface-First)
|
|||
|
|
│ └── */ # 各模块 Store
|
|||
|
|
│ ├── interface.ts # 接口定义
|
|||
|
|
│ └── store.ts # 实现代码
|
|||
|
|
├── types/ # TypeScript 类型定义
|
|||
|
|
├── hooks/ # 自定义 Hooks
|
|||
|
|
├── lib/ # 核心工具库
|
|||
|
|
├── styles/ # 全局样式
|
|||
|
|
├── prisma/ # 数据库 Schema
|
|||
|
|
└── docs/ # 项目文档
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 架构设计
|
|||
|
|
|
|||
|
|
### 数据流架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
客户端组件
|
|||
|
|
↓
|
|||
|
|
Server Action ('use server')
|
|||
|
|
↓
|
|||
|
|
Store 接口 (stores/*/interface.ts)
|
|||
|
|
↓
|
|||
|
|
Store 实现 (stores/*/store.ts)
|
|||
|
|
↓
|
|||
|
|
Prisma ORM
|
|||
|
|
↓
|
|||
|
|
MySQL/MariaDB
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 权限管理
|
|||
|
|
|
|||
|
|
- **角色定义**:`role = 1` 管理员,`role = 2` 普通用户
|
|||
|
|
- **权限守卫**:使用 `checkAdmin()` 保护敏感操作
|
|||
|
|
- **自动提权**:首个注册用户自动获得管理员权限
|
|||
|
|
|
|||
|
|
### Server Action 设计规范
|
|||
|
|
|
|||
|
|
项目采用 **Interface-First** 模式:
|
|||
|
|
|
|||
|
|
1. **Interface**(`stores/*/interface.ts`):定义 Store 接口
|
|||
|
|
2. **Implementation**(`stores/*/store.ts`):实现业务逻辑
|
|||
|
|
3. **Action**(`app/actions/*.ts`):统一错误处理、缓存更新
|
|||
|
|
|
|||
|
|
## 代码规范
|
|||
|
|
|
|||
|
|
### 命名约定
|
|||
|
|
|
|||
|
|
| 类型 | 规则 | 示例 |
|
|||
|
|
| --------- | -------------- | --------------- |
|
|||
|
|
| 文件 | Kebab Case | `blog-list.tsx` |
|
|||
|
|
| 组件 | Pascal Case | `BlogList` |
|
|||
|
|
| 变量/函数 | lowerCamelCase | `fetchBlogData` |
|
|||
|
|
| 类型 | Pascal Case | `IBlogStore` |
|
|||
|
|
|
|||
|
|
### 交互组件规范 (NiceModal)
|
|||
|
|
|
|||
|
|
Dialog、Alert、Drawer 组件必须统一通过 NiceModal 管理:
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
// 定义组件
|
|||
|
|
export const ExampleDialog = NiceModal.create(({ data, onSuccess }) => {
|
|||
|
|
const modal = NiceModal.useModal();
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Dialog open={modal.visible} onOpenChange={modal.remove}>
|
|||
|
|
<DialogContent>
|
|||
|
|
<Button onClick={() => modal.remove()}>取消</Button>
|
|||
|
|
</DialogContent>
|
|||
|
|
</Dialog>
|
|||
|
|
);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 使用组件
|
|||
|
|
NiceModal.show(ExampleDialog, { data, onSuccess: () => mutate() });
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 设计系统
|
|||
|
|
|
|||
|
|
项目遵循 **Chen Serif 设计系统**(Variant-driven Design 方案),基于 Tailwind CSS v4 + shadcn/ui 理念构建。
|
|||
|
|
|
|||
|
|
### 核心理念
|
|||
|
|
|
|||
|
|
**Variant-driven Design**(变体驱动设计):组件通过 props 管理变体(`variant`、`size`),而非全局 CSS 类名。
|
|||
|
|
|
|||
|
|
### 配色方案
|
|||
|
|
|
|||
|
|
| 类别 | Token | 值 | 用途 |
|
|||
|
|
| -------- | ------------------- | ------------------------ | -------------- |
|
|||
|
|
| 背景 | `--color-bg` | `#050505` | 页面背景 |
|
|||
|
|
| 文字 | `--color-fg` | `#ebebeb` | 主文字 |
|
|||
|
|
| 品牌 | `--color-primary` | `#10b981` | 主强调色(翡翠绿) |
|
|||
|
|
| 卡片 | `--color-card` | `rgba(255,255,255,0.02)` | 卡片背景 |
|
|||
|
|
| 表面 | `--color-surface` | `rgba(255,255,255,0.08)` | 次级背景 |
|
|||
|
|
| 次级文字 | `--color-muted` | `rgba(255,255,255,0.4)` | 次级文字 |
|
|||
|
|
| 边框 | `--color-border` | `rgba(255,255,255,0.08)` | 边框 |
|
|||
|
|
|
|||
|
|
### 字体体系
|
|||
|
|
|
|||
|
|
字体使用 jsDelivr CDN @fontsource,通过 `@font-face` 定义可变字体。
|
|||
|
|
|
|||
|
|
| 用途 | 字体 | Token | 字重范围 |
|
|||
|
|
| ---------- | ------------- | -------------- | --------------- |
|
|||
|
|
| 标题/强调 | Newsreader | `--font-serif` | 200-800(可变) |
|
|||
|
|
| 正文/UI | Inter | `--font-sans` | 100-900(可变) |
|
|||
|
|
| 代码/技术 | Space Grotesk | `--font-mono` | 300-700(可变) |
|
|||
|
|
|
|||
|
|
**使用示例:**
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
<h1 className="font-serif">Newsreader 标题</h1>
|
|||
|
|
<p className="font-sans">Inter 正文字体</p>
|
|||
|
|
<code className="font-mono">Space Grotesk 等宽</code>
|
|||
|
|
<p className="font-serif italic">Newsreader 斜体</p>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 组件示例
|
|||
|
|
|
|||
|
|
```tsx
|
|||
|
|
<Button variant="primary">新建文章</Button>
|
|||
|
|
<Button variant="secondary">取消</Button>
|
|||
|
|
<Button variant="ghost">了解更多</Button>
|
|||
|
|
|
|||
|
|
<Badge variant="success">成功</Badge>
|
|||
|
|
<Badge variant="warning">警告</Badge>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
详细设计规范请参考 [docs/chen-serif-design-system.md](./docs/chen-serif-design-system.md)。
|
|||
|
|
|
|||
|
|
## 部署
|
|||
|
|
|
|||
|
|
### Docker 部署
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
docker build -t fuxiaochen .
|
|||
|
|
docker run -p 3000:3000 fuxiaochen
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PM2 部署
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pnpm build
|
|||
|
|
pnpm pm2:start
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 贡献指南
|
|||
|
|
|
|||
|
|
1. Fork 本仓库
|
|||
|
|
2. 创建功能分支(`git checkout -b feature/amazing-feature`)
|
|||
|
|
3. 提交变更(`git commit -m 'feat: add amazing feature'`)
|
|||
|
|
4. 推送分支(`git push origin feature/amazing-feature`)
|
|||
|
|
5. 创建 Pull Request
|
|||
|
|
|
|||
|
|
### Commit 规范
|
|||
|
|
|
|||
|
|
遵循 Conventional Commits:
|
|||
|
|
|
|||
|
|
- `feat`:新功能
|
|||
|
|
- `fix`:Bug 修复
|
|||
|
|
- `docs`:文档更新
|
|||
|
|
- `style`:代码格式
|
|||
|
|
- `refactor`:重构
|
|||
|
|
- `perf`:性能优化
|
|||
|
|
- `test`:测试
|
|||
|
|
- `chore`:构建/工具
|
|||
|
|
|
|||
|
|
## Star 历史
|
|||
|
|
|
|||
|
|
<a href="https://www.star-history.com/#aifuxi/fuxiaochen&type=date&legend=top-left">
|
|||
|
|
<picture>
|
|||
|
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=aifuxi/fuxiaochen&type=date&theme=dark&legend=top-left" />
|
|||
|
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=aifuxi/fuxiaochen&type=date&legend=top-left" />
|
|||
|
|
<img alt="Star 历史图表" src="https://api.star-history.com/svg?repos=aifuxi/fuxiaochen&type=date&legend=top-left" />
|
|||
|
|
</picture>
|
|||
|
|
</a>
|
|||
|
|
|
|||
|
|
## 许可证
|
|||
|
|
|
|||
|
|
MIT License
|
|||
|
|
|
|||
|
|
## 作者
|
|||
|
|
|
|||
|
|
[fuxiaochen](https://github.com/aifuxi)
|