Files
KVideo/CONTRIBUTING.md
T
kuekhaoyang 3940d8e339 feat: 添加贡献指南和许可证文件
- 新增 CONTRIBUTING.md 文件,包含贡献流程、行为准则、开发指南等内容
- 新增 LICENSE 文件,采用 MIT 许可证
2025-11-18 14:16:42 +08:00

775 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 贡献指南
感谢您对 KVideo 项目的关注!我们热烈欢迎任何形式的贡献,包括但不限于:
- 🐛 报告 Bug
- 💡 提出新功能建议
- 📝 改进文档
- 🎨 优化 UI/UX
- ✨ 提交代码修复或新功能
## 目录
- [行为准则](#行为准则)
- [如何贡献](#如何贡献)
- [报告 Bug](#报告-bug)
- [提出功能建议](#提出功能建议)
- [提交代码](#提交代码)
- [开发指南](#开发指南)
- [环境搭建](#环境搭建)
- [代码规范](#代码规范)
- [提交规范](#提交规范)
- [Liquid Glass UI 设计规范](#liquid-glass-ui-设计规范)
- [核心原则](#核心原则)
- [组件设计准则](#组件设计准则)
- [CSS 变量系统](#css-变量系统)
- [动画规范](#动画规范)
- [测试指南](#测试指南)
- [文档规范](#文档规范)
## 行为准则
本项目遵循 [Contributor Covenant](https://www.contributor-covenant.org/) 行为准则。参与本项目即表示您同意遵守其条款。
我们承诺提供一个开放、友好、包容的社区环境:
- 尊重不同的观点和经验
- 优雅地接受建设性批评
- 关注对社区最有利的事情
- 对其他社区成员保持同理心
## 如何贡献
### 报告 Bug
如果您发现了 Bug,请通过 [GitHub Issues](https://github.com/KuekHaoYang/kvideo/issues) 报告。报告时请包含:
1. **清晰的标题** - 简明扼要地描述问题
2. **重现步骤** - 详细说明如何触发 Bug
3. **预期行为** - 描述您期望的正常行为
4. **实际行为** - 描述实际发生了什么
5. **环境信息**
- 浏览器版本(如 Chrome 120
- 操作系统(如 macOS 14.0
- Node.js 版本(如 20.10.0
6. **截图/视频**(如适用)
7. **控制台错误**(如有)
**Bug 报告模板:**
```markdown
### 问题描述
[清晰描述 Bug]
### 重现步骤
1. 进入 '...'
2. 点击 '...'
3. 滚动到 '...'
4. 看到错误
### 预期行为
[描述预期的正常行为]
### 实际行为
[描述实际发生的情况]
### 截图
[如果适用,添加截图]
### 环境
- 浏览器: [如 Chrome 120]
- 操作系统: [如 macOS 14.0]
- Node.js 版本: [如 20.10.0]
### 额外信息
[任何其他有助于解决问题的信息]
```
### 提出功能建议
我们欢迎新功能建议!请通过 [GitHub Issues](https://github.com/KuekHaoYang/kvideo/issues) 提交,并包含:
1. **功能概述** - 简要描述功能
2. **使用场景** - 说明为什么需要这个功能
3. **详细设计** - 描述功能如何工作
4. **UI 设计**(如适用)- 提供设计稿或草图
5. **技术实现思路**(可选)
### 提交代码
1. **Fork 仓库**
```bash
# 点击 GitHub 页面右上角的 "Fork" 按钮
```
2. **克隆您的 Fork**
```bash
git clone https://github.com/YOUR_USERNAME/kvideo.git
cd kvideo
```
3. **创建特性分支**
```bash
git checkout -b feature/your-feature-name
# 或
git checkout -b fix/your-bug-fix
```
4. **安装依赖**
```bash
npm install
```
5. **进行开发**
- 遵循 [代码规范](#代码规范)
- 遵循 [Liquid Glass UI 设计规范](#liquid-glass-ui-设计规范)
- 编写清晰的代码注释
6. **测试您的更改**
```bash
npm run dev # 启动开发服务器
npm run lint # 检查代码规范
npm run build # 确保构建成功
```
7. **提交更改**
```bash
git add .
git commit -m "feat: 添加某个功能"
# 遵循提交规范(见下文)
```
8. **推送到您的 Fork**
```bash
git push origin feature/your-feature-name
```
9. **创建 Pull Request**
- 前往原仓库页面
- 点击 "New Pull Request"
- 填写 PR 模板
- 等待代码审查
## 开发指南
### 环境搭建
**系统要求:**
- Node.js 20.x 或更高
- npm 9.x 或 pnpm 8.x
- Git 2.x
**快速开始:**
```bash
# 克隆仓库
git clone https://github.com/YOUR_USERNAME/kvideo.git
cd kvideo
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 打开浏览器访问 http://localhost:3000
```
### 代码规范
#### TypeScript 规范
- **严格模式** - 启用 `strict: true`
- **类型注解** - 所有函数参数和返回值必须有类型
- **避免 `any`** - 使用具体类型或 `unknown`
- **接口优先** - 优先使用 `interface` 而非 `type`
```typescript
// ✅ 好的示例
interface VideoProps {
id: string;
title: string;
onPlay: (url: string) => void;
}
function VideoCard({ id, title, onPlay }: VideoProps): JSX.Element {
return <div>{title}</div>;
}
// ❌ 不好的示例
function VideoCard(props: any) {
return <div>{props.title}</div>;
}
```
#### React 组件规范
- **函数组件** - 使用函数组件和 Hooks
- **命名规范** - PascalCase 命名组件文件
- **单一职责** - 每个组件只做一件事
- **文件大小** - 单个文件不超过 150 行(严格遵守)
- **Props 解构** - 在函数参数中解构 props
```typescript
// ✅ 好的示例 - SearchForm.tsx
'use client';
interface SearchFormProps {
onSubmit: (query: string) => void;
placeholder?: string;
}
export function SearchForm({ onSubmit, placeholder = '搜索视频...' }: SearchFormProps) {
// 组件逻辑(不超过 150 行)
}
```
#### 文件组织规范
```
components/
├── search/ # 功能分组
│ ├── SearchForm.tsx # 主组件
│ ├── VideoGrid.tsx
│ └── index.ts # 导出文件
├── player/
└── ui/ # 通用 UI 组件
├── Button.tsx
├── Card.tsx
└── Input.tsx
```
#### 命名规范
| 类型 | 规范 | 示例 |
|------|------|------|
| 组件 | PascalCase | `VideoPlayer`, `SearchForm` |
| 函数 | camelCase | `handleSearch`, `fetchVideoData` |
| 常量 | UPPER_SNAKE_CASE | `API_BASE_URL`, `MAX_RESULTS` |
| 接口 | PascalCase + 描述性 | `VideoPlayerProps`, `SearchResult` |
| 类型 | PascalCase | `VideoData`, `PlayerState` |
| Hook | use + PascalCase | `useVideoPlayer`, `useSearchCache` |
### 提交规范
我们遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范:
**格式:**
```
<type>(<scope>): <subject>
<body>
<footer>
```
**类型(type):**
| 类型 | 说明 |
|------|------|
| `feat` | 新功能 |
| `fix` | Bug 修复 |
| `docs` | 文档更新 |
| `style` | 代码格式(不影响功能) |
| `refactor` | 重构(既不是新功能也不是 Bug 修复) |
| `perf` | 性能优化 |
| `test` | 添加测试 |
| `chore` | 构建过程或辅助工具的变动 |
| `ui` | UI/UX 改进 |
**示例:**
```bash
# 新功能
git commit -m "feat(search): 添加实时流式搜索功能"
# Bug 修复
git commit -m "fix(player): 修复 HLS 流加载失败问题"
# UI 改进
git commit -m "ui(card): 优化视频卡片悬停动画效果"
# 文档
git commit -m "docs(readme): 更新安装步骤说明"
# 重构
git commit -m "refactor(api): 提取搜索逻辑到独立模块"
```
## Liquid Glass UI 设计规范
KVideo 严格遵循 **Liquid Glass** 设计系统。所有 UI 贡献必须符合以下规范。
### 核心原则
#### 1. 玻璃效果(Glass Effect
所有容器类组件必须使用毛玻璃效果:
```css
.glass-container {
background: var(--glass-bg);
backdrop-filter: blur(25px) saturate(180%);
-webkit-backdrop-filter: blur(25px) saturate(180%);
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-md);
}
```
#### 2. 通用柔软度(Universal Softness
**只使用两种圆角:**
- **`rounded-2xl` (1.5rem)** - 用于容器类组件
- **`rounded-full` (9999px)** - 用于圆形/胶囊组件
```typescript
// ✅ 正确示例
<div className="... rounded-2xl"> {/* 卡片 */}
<button className="... rounded-2xl"> {/* 按钮 */}
<input className="... rounded-2xl"> {/* 输入框 */}
<div className="... rounded-full"> {/* 头像 */}
<span className="... rounded-full"> {/* 徽章 */}
// ❌ 错误示例
<div className="... rounded-lg"> {/* 不使用其他圆角值 */}
<div className="... rounded-md">
<div className="... rounded">
```
#### 3. 流体动画(Fluid Animation
使用物理感知的缓动曲线:
```css
.animated-element {
transition: all var(--transition-fluid);
/* 等价于: transition: all 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); */
}
```
#### 4. 光学交互(Lensing & Light Interaction
悬停时添加内发光效果:
```css
.interactive-element:hover {
transform: translateY(-2px);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 30%, transparent);
}
```
#### 5. 层次分明(Depth & Hierarchy
使用两级阴影:
```css
--shadow-sm: 0 2px 4px var(--shadow-color);
--shadow-md: 0 4px 12px var(--shadow-color);
```
### 组件设计准则
#### 按钮组件
```typescript
// Button.tsx
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
onClick?: () => void;
}
export function Button({ variant = 'primary', size = 'md', children, onClick }: ButtonProps) {
return (
<button
className={`
inline-flex items-center justify-center
font-semibold transition-all duration-[400ms]
rounded-2xl shadow-[var(--shadow-sm)]
hover:transform hover:translate-y-[-2px]
hover:shadow-[var(--shadow-md)]
active:transform active:translate-y-0 active:scale-[0.98]
${variant === 'primary' && 'bg-[var(--accent-color)] text-white'}
${variant === 'secondary' && 'bg-[var(--glass-bg)] border border-[var(--glass-border)]'}
${size === 'md' && 'px-5 py-3 text-base'}
`}
onClick={onClick}
>
{children}
</button>
);
}
```
#### 卡片组件
```typescript
// Card.tsx
interface CardProps {
children: React.ReactNode;
hover?: boolean;
}
export function Card({ children, hover = true }: CardProps) {
return (
<div
className={`
bg-[var(--glass-bg)] backdrop-blur-[25px] saturate-[180%]
border border-[var(--glass-border)] rounded-2xl
shadow-[var(--shadow-md)] p-6
transition-all duration-[400ms]
${hover && 'hover:transform hover:translate-y-[-5px] hover:scale-[1.02]'}
`}
>
{children}
</div>
);
}
```
#### 输入框组件
```typescript
// Input.tsx
interface InputProps {
placeholder?: string;
value: string;
onChange: (value: string) => void;
}
export function Input({ placeholder, value, onChange }: InputProps) {
return (
<input
type="text"
placeholder={placeholder}
value={value}
onChange={(e) => onChange(e.target.value)}
className="
w-full bg-[var(--glass-bg)] backdrop-blur-[10px]
border border-[var(--glass-border)] rounded-2xl
px-4 py-3 text-base text-[var(--text-color)]
transition-all duration-[400ms]
focus:outline-none focus:border-[var(--accent-color)]
focus:shadow-[0_0_0_3px_color-mix(in_srgb,var(--accent-color)_30%,transparent)]
"
/>
);
}
```
### CSS 变量系统
所有样式必须使用 CSS 变量,确保主题切换正常工作:
```css
/* globals.css */
:root {
/* 字体 */
--font-family-system: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
/* 浅色主题 */
--bg-color-light: #f0f2f5;
--text-color-light: #1d1d1f;
--accent-color-light: #007aff;
--glass-bg-light: rgba(242, 242, 247, 0.8);
--glass-border-light: rgba(255, 255, 255, 0.5);
--shadow-color-light: rgba(0, 0, 0, 0.1);
/* 深色主题 */
--bg-color-dark: #121212;
--text-color-dark: #f5f5f7;
--accent-color-dark: #0a84ff;
--glass-bg-dark: rgba(28, 28, 30, 0.75);
--glass-border-dark: rgba(60, 60, 60, 0.7);
--shadow-color-dark: rgba(0, 0, 0, 0.3);
/* 圆角 */
--radius-2xl: 1.5rem;
--radius-full: 9999px;
/* 阴影 */
--shadow-sm: 0 2px 4px var(--shadow-color);
--shadow-md: 0 4px 12px var(--shadow-color);
/* 动画 */
--transition-fluid: 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
body {
--bg-color: var(--bg-color-light);
--text-color: var(--text-color-light);
--accent-color: var(--accent-color-light);
--glass-bg: var(--glass-bg-light);
--glass-border: var(--glass-border-light);
--shadow-color: var(--shadow-color-light);
}
body.dark-mode {
--bg-color: var(--bg-color-dark);
--text-color: var(--text-color-dark);
--accent-color: var(--accent-color-dark);
--glass-bg: var(--glass-bg-dark);
--glass-border: var(--glass-border-dark);
--shadow-color: var(--shadow-color-dark);
}
```
**使用示例:**
```typescript
// ✅ 正确 - 使用 CSS 变量
<div style={{
background: 'var(--glass-bg)',
borderRadius: 'var(--radius-2xl)',
color: 'var(--text-color)'
}} />
// ❌ 错误 - 硬编码颜色
<div style={{
background: '#f0f2f5',
borderRadius: '1.5rem',
color: '#1d1d1f'
}} />
```
### 动画规范
#### 悬停动画
```typescript
<div className="
transition-all duration-[400ms]
hover:transform hover:translate-y-[-5px] hover:scale-[1.02]
hover:shadow-[var(--shadow-md)]
">
```
#### 点击动画
```typescript
<button className="
active:transform active:translate-y-0 active:scale-[0.98]
">
```
#### 淡入动画
```typescript
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
```
### 响应式设计
使用 Tailwind 的响应式前缀:
```typescript
<div className="
grid grid-cols-1 gap-4
sm:grid-cols-2
md:grid-cols-3
lg:grid-cols-4
xl:grid-cols-5
">
```
**断点定义:**
| 前缀 | 最小宽度 | 适用设备 |
|------|---------|---------|
| `sm` | 640px | 平板竖屏 |
| `md` | 768px | 平板横屏 |
| `lg` | 1024px | 笔记本 |
| `xl` | 1280px | 桌面 |
| `2xl` | 1536px | 大屏 |
### UI 检查清单
提交 UI 相关的 PR 前,请确保:
- [ ] 所有容器使用 `rounded-2xl`
- [ ] 所有圆形元素使用 `rounded-full`
- [ ] 使用毛玻璃效果 `backdrop-filter: blur(25px) saturate(180%)`
- [ ] 使用 CSS 变量而非硬编码颜色
- [ ] 悬停时有流体动画效果
- [ ] 支持深浅色主题
- [ ] 在移动端和桌面端测试过
- [ ] 无控制台警告或错误
- [ ] 代码通过 ESLint 检查
## 测试指南
### 手动测试
在提交 PR 前,请确保:
1. **功能测试**
- [ ] 新功能按预期工作
- [ ] 没有破坏现有功能
- [ ] 边界情况处理正确
2. **浏览器测试**
- [ ] Chrome(最新版本)
- [ ] Safari(最新版本)
- [ ] Firefox(最新版本)
- [ ] Edge(最新版本)
3. **响应式测试**
- [ ] 移动端(375px - 428px
- [ ] 平板(768px - 1024px
- [ ] 桌面(1280px+
4. **主题测试**
- [ ] 浅色主题显示正常
- [ ] 深色主题显示正常
- [ ] 主题切换平滑
5. **性能测试**
- [ ] 页面加载时间 < 3 秒
- [ ] 动画流畅(60fps
- [ ] 无内存泄漏
### 构建测试
```bash
# 开发环境
npm run dev
# 生产构建
npm run build
# 检查构建产物
npm start
# 代码检查
npm run lint
```
## 文档规范
### 代码注释
- **函数注释** - 使用 JSDoc 格式
- **复杂逻辑** - 添加行内注释说明
- **TODO** - 使用 `// TODO:` 标记待办事项
```typescript
/**
* 并行搜索视频
* @param query - 搜索关键词
* @param sources - 视频源列表
* @returns 搜索结果数组
*/
async function searchVideos(
query: string,
sources: VideoSource[]
): Promise<SearchResult[]> {
// TODO: 添加缓存机制
const results = await Promise.all(
sources.map(source => fetchFromSource(source, query))
);
return results.filter(Boolean);
}
```
### README 更新
如果您的更改影响到以下内容,请更新 README:
- 添加新功能
- 修改安装步骤
- 更新依赖项
- 添加新的 API
## Pull Request 指南
### PR 标题
遵循 Conventional Commits 格式:
```
feat(search): 添加实时流式搜索功能
fix(player): 修复视频加载失败问题
docs(readme): 更新安装步骤
ui(card): 优化卡片悬停效果
```
### PR 描述模板
```markdown
## 变更类型
- [ ] 新功能
- [ ] Bug 修复
- [ ] 性能优化
- [ ] 重构
- [ ] 文档更新
- [ ] UI/UX 改进
## 变更描述
[清晰描述您做了什么改动]
## 相关 Issue
Closes #[issue 编号]
## 测试
- [ ] 本地测试通过
- [ ] 多浏览器测试
- [ ] 响应式测试
- [ ] 主题切换测试
## 截图
[如果是 UI 改动,添加前后对比截图]
## 检查清单
- [ ] 代码遵循项目规范
- [ ] 已添加必要的注释
- [ ] 已更新相关文档
- [ ] 无 ESLint 警告
- [ ] 通过所有测试
- [ ] UI 符合 Liquid Glass 设计规范
```
### 代码审查
PR 提交后,维护者会进行代码审查。请:
- 及时回复审查意见
- 根据反馈修改代码
- 保持讨论友好和专业
- 学习和理解审查意见
## 获得帮助
如果您在贡献过程中遇到问题:
1. **查看文档** - 阅读 README 和本贡献指南
2. **搜索 Issues** - 查看是否有类似问题
3. **提问** - 在 [GitHub Discussions](https://github.com/KuekHaoYang/kvideo/discussions) 提问
4. **联系维护者** - 通过 Issues 联系项目维护者
## 致谢
感谢所有为 KVideo 做出贡献的开发者!您的努力让这个项目变得更好。
---
<p align="center">
再次感谢您的贡献!✨<br>
让我们一起打造最优雅的视频聚合平台
</p>