diff --git a/.gitignore b/.gitignore index e074f5d..d2b9c5b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ todos.json /.claude/reviews/ docs/MODULE_COMPLETION_REPORT.md src/routeTree.gen.ts +.reports/ +tanstack-start/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6ed71ba --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- Article search functionality +- Virtual article list with infinite scroll + +### Changed +- Refactored article routing structure + +### Fixed +- Real-time like count updates after liking articles + +## [0.1.0] - 2026-05-20 + +### Added +- Initial release +- User authentication (email/password + OTP) +- Article writing with Tiptap editor +- Article listing and detail pages +- User profiles and settings +- Avatar upload via Cloudflare R2 +- Email notifications via Resend +- Dark/light theme toggle +- Responsive layout with sidebar + +### Technical +- TanStack Start (React SSR) +- TanStack Router (file-based routing) +- TanStack Query (data fetching) +- Prisma + PostgreSQL +- Better Auth +- Tailwind CSS v4 + Shadcn/UI +- Vitest testing setup + +--- + +[Unreleased]: https://github.com/Rinisnotarobot/cedium/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/Rinisnotarobot/cedium/releases/tag/v0.1.0 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c3f0085 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,409 @@ +# Contributing to Cedium + +首先,感谢你考虑为 Cedium 做贡献!正是像你这样的人让 Cedium 成为一个更好的创作平台。 + +## 目录 + +- [如何贡献](#如何贡献) +- [开发环境设置](#开发环境设置) +- [项目结构](#项目结构) +- [代码风格指南](#代码风格指南) +- [提交规范](#提交规范) +- [Pull Request 流程](#pull-request-流程) +- [报告 Bug](#报告-bug) +- [提出新功能](#提出新功能) +- [行为准则](#行为准则) +- [获得帮助](#获得帮助) + +--- + +## 如何贡献 + +### 贡献方式 + +我们欢迎多种形式的贡献: + +- 🐛 **报告 Bug** — 提交 Issue 描述问题 +- 💡 **提出功能** — 分享你的想法和需求 +- 📝 **改进文档** — 修正错漏、补充说明 +- 🔧 **修复 Bug** — 提交 PR 解决已知问题 +- ✨ **添加功能** — 实现新特性 +- 🌐 **翻译** — 帮助项目支持更多语言 + +### 开始之前 + +在开始贡献之前,请确保: + +1. 你已经阅读了 [README.md](README.md) +2. 你已经熟悉项目的技术栈 +3. 你已经设置好开发环境(见下一节) + +--- + +## 开发环境设置 + +### 前置要求 + +| 工具 | 版本 | 说明 | +|------|------|------| +| Node.js | 18+ | JavaScript 运行时 | +| pnpm | 8+ | 包管理器 | +| PostgreSQL | 15+ | 数据库 | + +### 安装步骤 + +1. **克隆仓库** + + ```bash + git clone https://github.com/Rinisnotarobot/cedium.git + cd cedium + ``` + +2. **安装依赖** + + ```bash + pnpm install + ``` + +3. **配置环境变量** + + ```bash + cp .env.example .env.local + ``` + + 编辑 `.env.local`,填写必需的环境变量(参见 [README.md](README.md#环境变量))。 + +4. **初始化数据库** + + ```bash + pnpm db:generate # 生成 Prisma Client + pnpm db:push # 推送数据库结构 + pnpm db:seed # 填充种子数据(可选) + ``` + +5. **启动开发服务器** + + ```bash + pnpm dev + ``` + + 访问 http://localhost:3000 验证一切正常。 + +### 运行测试 + +```bash +pnpm test # 运行所有测试 +pnpm test -- watch # 监听模式 +``` + +--- + +## 项目结构 + +熟悉项目结构有助于你快速定位代码: + +``` +src/ +├── components/ # UI 组件 +├── data/ # Server Functions (TanStack Start) +├── hooks/ # TanStack Query hooks +├── lib/ # 核心配置(auth、validators) +├── routes/ # 文件路由 +├── types/ # TypeScript 类型定义 +└── generated/ # Prisma 生成的类型 +``` + +详细结构请参考 [README.md](README.md#项目结构)。 + +--- + +## 代码风格指南 + +### TypeScript + +- **避免 `any` 类型** — 使用具体类型或 `unknown` +- **使用严格模式** — 项目已启用 TypeScript strict +- **命名约定**: + - 变量/函数:`camelCase` + - 组件/类型/接口:`PascalCase` + - 常量:`UPPER_SNAKE_CASE` + - 文件名:与导出内容一致 + +### React + +- **使用函数组件** — 项目使用 React 19 + Compiler +- **保持组件简洁** — 单一职责,< 50 行 +- **避免手动 memo** — React Compiler 自动处理 + +### CSS + +- **使用 Tailwind CSS** — 遵循项目现有的样式约定 +- **自定义样式** — 放在 `styles.css` 或组件内 + +### 文件组织 + +- **一个文件一个主要导出** +- **文件大小** — 控制在 800 行以内 +- **目录结构** — 按功能模块组织 + +--- + +## 提交规范 + +我们使用 [Conventional Commits](https://www.conventionalcommits.org/) 规范: + +### 格式 + +``` +<类型>: <描述> + +[可选的详细说明] + +[可选的脚注] +``` + +### 类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| `feat` | 新功能 | `feat: 添加文章搜索功能` | +| `fix` | Bug 修复 | `fix: 修复登录重定向问题` | +| `docs` | 文档更新 | `docs: 更新安装说明` | +| `style` | 样式调整(不影响逻辑) | `style: 调整按钮间距` | +| `refactor` | 重构(不改变功能) | `refactor: 重构认证逻辑` | +| `perf` | 性能优化 | `perf: 优化文章列表渲染` | +| `test` | 测试相关 | `test: 添加用户注册测试` | +| `chore` | 构建/工具变更 | `chore: 更新依赖版本` | + +### 规则 + +- **使用中文描述** — 项目面向中文用户 +- **首字母小写** — 描述不以大写开头 +- **不以句号结尾** — 描述末尾不加句号 +- **原子提交** — 一个提交只做一件事 + +--- + +## Pull Request 流程 + +### 创建 PR 之前的检查清单 + +- [ ] 代码通过 `pnpm test` +- [ ] 代码符合风格指南 +- [ ] 提交消息符合规范 +- [ ] 更新了相关文档 +- [ ] 添加了必要的测试 + +### 步骤 + +1. **创建分支** + + ```bash + git checkout -b feat/your-feature-name + # 或 + git checkout -b fix/your-bug-fix + ``` + + 分支命名建议: + - `feat/xxx` — 新功能 + - `fix/xxx` — Bug 修复 + - `refactor/xxx` — 重构 + - `docs/xxx` — 文档 + +2. **编写代码** + + 确保代码符合风格指南,并添加必要的测试。 + +3. **提交变更** + + ```bash + git add . + git commit -m "feat: 添加新功能描述" + ``` + +4. **推送分支** + + ```bash + git push origin feat/your-feature-name + ``` + +5. **创建 Pull Request** + + - 在 GitHub 上打开 Pull Request + - 清晰描述 PR 的目的和变更内容 + - 关联相关 Issue(如 `Closes #123`) + - 等待代码审查 + +### PR 标题格式 + +使用与提交消息相同的格式: + +``` +feat: 添加文章搜索功能 +fix: 修复登录重定向问题 +``` + +### PR 模板 + +创建 PR 时,请包含以下信息: + +```markdown +## 变更说明 + +简要描述此 PR 解决的问题或添加的功能。 + +## 变更类型 + +- [ ] Bug 修复 +- [ ] 新功能 +- [ ] 重构 +- [ ] 文档更新 +- [ ] 其他 + +## 测试说明 + +描述如何测试这些变更。 + +## 相关 Issue + +Closes #xxx +``` + +--- + +## 报告 Bug + +### 提交 Bug 之前的检查 + +- [ ] 搜索现有 Issues,确认问题未被报告 +- [ ] 使用最新版本测试,确认问题仍存在 +- [ ] 收集必要的调试信息 + +### 如何提交 Bug + +打开一个新的 Issue,包含以下信息: + +**标题**:简洁描述问题 + +**描述**: + +```markdown +## 问题描述 + +清晰描述遇到的问题。 + +## 复现步骤 + +1. 打开 '...' +2. 点击 '...' +3. 看到错误 '...' + +## 预期行为 + +描述你期望发生什么。 + +## 实际行为 + +描述实际发生了什么。 + +## 环境信息 + +- 浏览器: [例如 Chrome 120] +- 操作系统: [例如 Windows 11] +- Node 版本: [例如 18.17.0] + +## 截图/日志 + +如果适用,添加截图或错误日志。 +``` + +--- + +## 提出新功能 + +我们欢迎新功能建议! + +### 提交之前的考虑 + +- 功能是否符合项目定位? +- 是否有现有 Issue 已提出类似想法? +- 功能是否足够通用,对大多数用户有帮助? + +### 如何提交功能建议 + +打开一个新的 Issue,使用 `enhancement` 标签: + +```markdown +## 功能描述 + +清晰描述你希望添加的功能。 + +## 使用场景 + +描述什么情况下需要此功能。 + +## 可能的实现方案 + +如果有想法,简要描述可能的实现方式。 + +## 替代方案 + +描述你考虑过的其他解决方案。 + +## 额外信息 + +任何其他相关信息或截图。 +``` + +--- + +## 行为准则 + +### 我们的承诺 + +为了营造开放和友好的环境,我们承诺: + +- 尊重不同观点和经验 +- 优雅地接受建设性批评 +- 关注对社区最有利的事情 +- 对其他社区成员表示同理心 + +### 不当行为 + +以下行为将被视为不当: + +- 使用性化语言或图像 +-侮辱性/贬损性评论 +- 公开或私下骚扰 +- 未经许可发布他人私人信息 +- 其他不道德或不专业的行为 + +### 执行 + +不当行为可能导致: + +- 警告 +- 临时禁止互动 +- 永久禁止参与项目 + +--- + +## 获得帮助 + +如果你在贡献过程中遇到问题,可以通过以下方式获得帮助: + +- **GitHub Issues** — 在 Issues 中提问 +- **GitHub Discussions** — 参与讨论(如果已启用) +- **邮件** — 聪明地描述你的问题,我们会尽快回复 + +--- + +## 致谢 + +感谢所有为 Cedium 做出贡献的人!你的每一份贡献都让这个项目变得更好。 + +贡献者将会在项目首页或 Release 说明中被提及。 + +--- + +再次感谢你的贡献!🎉 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0044b4d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Rinisnotarobot + +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. \ No newline at end of file diff --git a/README.md b/README.md index f17792c..880af9f 100644 --- a/README.md +++ b/README.md @@ -1,260 +1,281 @@ # Cedium -基于 TanStack Start 构建的全栈 Web 应用模板。 +> 一个现代化的创作平台,为写作者而生。 -## 技术栈 +[](LICENSE) [](CONTRIBUTING.md) [](https://tanstack.com/start) [](https://react.dev) [](https://typescriptlang.org) [](https://tailwindcss.com) [](https://prisma.io) -| 类别 | 技术 | -|------|------| -| 框架 | TanStack Start (React) | -| 路由 | TanStack Router (文件路由) | -| 数据获取 | TanStack Query | -| 表格 | TanStack Table | -| 表单 | TanStack Form + Zod | -| 数据库 | Prisma + PostgreSQL | -| 认证 | Better Auth | -| 样式 | Tailwind CSS v4 | -| UI 组件 | Shadcn/UI | -| 测试 | Vitest | -| 包管理 | pnpm | +
+ 🌐 在线演示 • + 核心功能 • + 技术栈 • + 快速开始 • + 项目结构 • + 贡献 +
-## 快速开始 +--- -### 安装依赖 +## 核心功能 -```bash -pnpm install -``` +### 📝 内容创作 -### 配置环境变量 +| 功能 | 说明 | +|------|------| +| **富文本编辑** | Tiptap 编辑器,支持 Markdown、代码高亮、表格、图片 | +| **草稿管理** | DRAFT / PUBLISHED / ARCHIVED 三种状态 | +| **标签系统** | 文章分类与标签关联 | +| **封面设置** | 自定义文章封面图片 | -创建 `.env.local` 文件,参考 `.env.example`: +### 👤 用户系统 - -| 变量 | 必需 | 说明 | 示例 | -|------|------|------|------| -| `DATABASE_URL` | 是 | PostgreSQL 连接字符串 | `postgresql://user:password@localhost:5432/cedium` | -| `BETTER_AUTH_URL` | 是 | Auth 服务 URL | `http://localhost:3000` | -| `BETTER_AUTH_SECRET` | 是 | Auth 密钥(运行 `npx @better-auth/cli secret` 生成) | 32位随机字符串 | -| `R2_ENDPOINT` | 是 | Cloudflare R2 存储端点 | `https://+ 如果这个项目对你有帮助,欢迎给一个 ⭐️ +
\ No newline at end of file diff --git a/dev.sh b/dev.sh new file mode 100755 index 0000000..5a09c10 --- /dev/null +++ b/dev.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# 查找并清除占用 3000 端口的进程 +PORT=3000 +PROCESS=$(lsof -t -i:$PORT 2>/dev/null) + +if [ -n "$PROCESS" ]; then + echo "发现进程占用端口 $PORT (PID: $PROCESS)" + kill -9 $PROCESS + echo "已清除进程" +fi + +# 启动开发服务器 +pnpm dev \ No newline at end of file diff --git a/src/components/articles/article-detail-page.tsx b/src/components/articles/article-detail-page.tsx index 201183d..768a770 100644 --- a/src/components/articles/article-detail-page.tsx +++ b/src/components/articles/article-detail-page.tsx @@ -152,8 +152,8 @@ export function ArticleDetailPage() { {article.tags.map((tag) => (暂无文章
-- 等待第一篇文章的发布... -
+{emptyMessage}
+ {!query && ( ++ 等待第一篇文章的发布... +
+ )}