diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..3e0523c
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,11 @@
+# 开发环境配置
+
+# API 配置(开发环境可以使用本地 API)
+VITE_API_BASE_URL=https://cfapi.searchgal.homes
+# VITE_API_BASE_URL=http://localhost:8787
+
+# 开发配置
+VITE_ENABLE_DEBUG=true
+VITE_ENABLE_MOCK=false
+
+# 其他配置继承自 .env
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..d2fbdf6
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,77 @@
+# SearchGal Frontend 环境变量配置模板
+# 复制此文件为 .env 并根据需要修改配置
+
+# ============================================
+# 应用信息
+# ============================================
+VITE_APP_TITLE=SearchGal - Galgame 聚合搜索
+VITE_APP_DESCRIPTION=多平台 Galgame 资源聚合搜索引擎
+VITE_APP_VERSION=1.0.0
+
+# ============================================
+# API 配置
+# ============================================
+VITE_API_BASE_URL=https://cfapi.searchgal.homes
+VITE_API_TIMEOUT=30000
+VITE_TRANSLATE_API_URL=https://translate.searchgal.homes
+VITE_VNDB_API_URL=https://api.vndb.org/kana/v1
+
+# ============================================
+# 外部服务
+# ============================================
+VITE_STATUS_URL=https://status.searchgal.homes
+VITE_ARTALK_SERVER=https://artalk.saop.cc
+VITE_IMAGE_API_URL=https://api.illlights.com/v1/img
+
+# ============================================
+# 网站信息
+# ============================================
+VITE_SITE_URL=https://searchgal.homes
+VITE_SITE_NAME=SearchGal
+VITE_GITHUB_URL=https://github.com/Moe-Sakura/frontend
+
+# ============================================
+# 功能开关
+# ============================================
+VITE_ENABLE_COMMENTS=true
+VITE_ENABLE_VNDB=true
+VITE_ENABLE_AI_TRANSLATE=true
+VITE_ENABLE_PWA=true
+VITE_ENABLE_ANALYTICS=false
+
+# ============================================
+# 搜索配置
+# ============================================
+VITE_SEARCH_COOLDOWN=30000
+VITE_DEFAULT_RESULTS_PER_PAGE=10
+VITE_LOAD_MORE_COUNT=20
+VITE_MAX_SEARCH_HISTORY=50
+
+# ============================================
+# 缓存配置(单位:毫秒)
+# ============================================
+VITE_CACHE_VNDB_DURATION=1800000
+VITE_CACHE_SEARCH_DURATION=600000
+VITE_CACHE_IMAGE_DURATION=3600000
+VITE_MAX_CACHE_SIZE=100
+
+# ============================================
+# 主题配置
+# ============================================
+VITE_THEME_PRIMARY=#ff1493
+VITE_THEME_ACCENT=#d946ef
+VITE_THEME_BACKGROUND_LIGHT=#fff5fa
+VITE_THEME_BACKGROUND_DARK=#1e293b
+
+# ============================================
+# 性能配置
+# ============================================
+VITE_QUICKLINK_DELAY=500
+VITE_QUICKLINK_LIMIT=10
+VITE_LAZY_LOAD_THRESHOLD=0.5
+
+# ============================================
+# 开发配置
+# ============================================
+VITE_ENABLE_DEBUG=false
+VITE_ENABLE_MOCK=false
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..5385a42
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,10 @@
+# 生产环境配置
+
+# API 配置
+VITE_API_BASE_URL=https://cfapi.searchgal.homes
+
+# 开发配置
+VITE_ENABLE_DEBUG=false
+VITE_ENABLE_MOCK=false
+
+# 其他配置继承自 .env
diff --git a/.gitignore b/.gitignore
index fe63289..5f4744a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,8 @@ dist-ssr
.history
.pnpm-store
.pnpm-lock.yaml
+
+# 环境变量文件
+.env
+.env.local
+.env.*.local
diff --git a/README.md b/README.md
index 8127d87..33a7a3e 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,9 @@
- 💬 **评论系统** - 基于 Artalk 的评论功能
- 🖼️ **随机背景** - IndexedDB 缓存的随机背景图片系统
- 📱 **响应式设计** - 完美适配桌面和移动设备
-- ⚡ **性能优化** - Pace.js 加载进度、Fancybox 图片预览、懒加载等
+- ⚡ **性能优化** - Pace.js 加载进度、Fancybox 图片预览、Lazysizes 懒加载、Quicklink 预加载
+- 📲 **PWA 支持** - 可安装为桌面/移动应用,支持离线访问
+- 📡 **RSS 订阅** - 订阅更新动态
## 🛠️ 技术栈
@@ -31,12 +33,14 @@
### UI 框架
- **Tailwind CSS 4.1** - 实用优先的 CSS 框架
-- **Font Awesome 7** - 图标库
+- **Lucide Icons** - 现代化 SVG 图标库
### 功能库
- **Artalk 2.9** - 评论系统
- **Fancybox 6** - 图片和内容预览
- **Pace.js 1.2** - 页面加载进度条
+- **Lazysizes 5.3** - 高性能图片懒加载
+- **Quicklink 2.3** - 智能预加载
### API 集成
- **Cloudflare Workers API** - 搜索聚合后端
@@ -55,6 +59,15 @@ git clone https://github.com/Moe-Sakura/frontend.git
cd frontend
```
+### 配置环境变量
+```bash
+# 复制环境变量模板
+cp .env.example .env
+
+# 根据需要修改 .env 文件中的配置
+# 详见 docs/ENV_GUIDE.md
+```
+
### 安装依赖
```bash
pnpm install
@@ -205,6 +218,13 @@ pnpm run build
项目不需要环境变量配置,所有 API 端点都在代码中硬编码或支持用户自定义。
+## 🤖 LLM 友好
+
+本项目遵循 [llms.txt](https://llmstxt.org/) 规范,为 AI 助手和大语言模型提供了结构化的项目文档。
+
+- 📄 访问 `/llms.txt` 获取项目的 LLM 友好文档
+- 🔗 在线地址: [searchgal.homes/llms.txt](https://searchgal.homes/llms.txt)
+
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
@@ -222,6 +242,31 @@ pnpm run build
- 使用 Tailwind CSS 进行样式编写
- 保持代码简洁和可读性
+## 📝 环境变量
+
+项目使用环境变量进行配置管理,所有配置项都可以通过 `.env` 文件进行自定义。
+
+### 快速配置
+
+```bash
+# 复制模板文件
+cp .env.example .env
+
+# 编辑配置(可选)
+vim .env
+```
+
+### 主要配置项
+
+- **API 地址**:`VITE_API_BASE_URL`
+- **功能开关**:`VITE_ENABLE_COMMENTS`、`VITE_ENABLE_VNDB` 等
+- **主题颜色**:`VITE_THEME_PRIMARY`、`VITE_THEME_ACCENT`
+- **性能配置**:缓存时长、搜索冷却时间等
+
+详细配置说明请查看:
+- 📘 [环境变量配置指南](./docs/ENV_GUIDE.md)
+- 📘 [环境变量使用示例](./docs/ENV_USAGE_EXAMPLES.md)
+
## 📄 许可证
本项目采用 [MIT](LICENSE) 许可证。
diff --git a/docs/ENV_CONFIG.md b/docs/ENV_CONFIG.md
new file mode 100644
index 0000000..be6829d
--- /dev/null
+++ b/docs/ENV_CONFIG.md
@@ -0,0 +1,270 @@
+# 环境变量配置指南
+
+SearchGal 使用 `.env` 文件进行全局配置管理。
+
+## 快速开始
+
+1. 复制示例文件:
+```bash
+cp .env.example .env
+```
+
+2. 根据需要修改 `.env` 文件中的配置
+
+3. 重启开发服务器使配置生效
+
+## 配置文件
+
+- `.env` - 本地环境配置(不提交到 Git)
+- `.env.example` - 配置示例(提交到 Git)
+- `src/config/env.ts` - 配置读取和类型定义
+
+## 使用方法
+
+### 方式 1:直接导入配置对象(推荐)
+
+```typescript
+import { CONFIG } from '@/config'
+
+// 使用 API 配置
+const apiUrl = CONFIG.api.defaultApiUrl
+console.log(apiUrl) // https://cfapi.searchgal.homes
+
+// 使用功能开关
+if (CONFIG.features.enableComments) {
+ // 初始化评论系统
+}
+
+// 使用搜索配置
+const cooldown = CONFIG.search.cooldown
+console.log(cooldown) // 30000
+```
+
+### 方式 2:按需导入
+
+```typescript
+import { API_CONFIG, FEATURE_FLAGS, SEARCH_CONFIG } from '@/config'
+
+// API 配置
+console.log(API_CONFIG.defaultApiUrl)
+
+// 功能开关
+console.log(FEATURE_FLAGS.enableVndb)
+
+// 搜索配置
+console.log(SEARCH_CONFIG.defaultMode)
+```
+
+### 方式 3:直接访问环境变量(不推荐)
+
+```typescript
+// ❌ 不推荐:需要手动处理类型和默认值
+const apiUrl = import.meta.env.VITE_DEFAULT_API_URL
+
+// ✅ 推荐:使用配置对象,有类型提示和默认值
+import { API_CONFIG } from '@/config'
+const apiUrl = API_CONFIG.defaultApiUrl
+```
+
+## 配置分类
+
+### 1. API 配置 (`API_CONFIG`)
+
+```typescript
+API_CONFIG.defaultApiUrl // 默认搜索 API
+API_CONFIG.vndbApiUrl // VNDB API
+API_CONFIG.translateApiUrl // AI 翻译 API
+API_CONFIG.statusApiUrl // 状态检查 API
+API_CONFIG.randomImageApi // 随机背景图片 API
+```
+
+### 2. 应用配置 (`APP_CONFIG`)
+
+```typescript
+APP_CONFIG.name // 应用名称
+APP_CONFIG.title // 应用标题
+APP_CONFIG.description // 应用描述
+APP_CONFIG.url // 网站 URL
+```
+
+### 3. 功能开关 (`FEATURE_FLAGS`)
+
+```typescript
+FEATURE_FLAGS.enablePwa // PWA 支持
+FEATURE_FLAGS.enableSw // Service Worker
+FEATURE_FLAGS.enableComments // 评论系统
+FEATURE_FLAGS.enableVndb // VNDB 集成
+FEATURE_FLAGS.enableTranslate // AI 翻译
+FEATURE_FLAGS.enableHistory // 搜索历史
+FEATURE_FLAGS.enableCache // 缓存系统
+FEATURE_FLAGS.enablePerformance // 性能监控
+FEATURE_FLAGS.enableDevLogs // 开发日志
+```
+
+### 4. 搜索配置 (`SEARCH_CONFIG`)
+
+```typescript
+SEARCH_CONFIG.defaultMode // 默认搜索模式
+SEARCH_CONFIG.cooldown // 搜索冷却时间(毫秒)
+SEARCH_CONFIG.defaultResultsPerPage // 默认显示结果数
+SEARCH_CONFIG.loadMoreCount // 每次加载更多的数量
+SEARCH_CONFIG.maxHistoryItems // 最大历史记录数
+```
+
+### 5. 缓存配置 (`CACHE_CONFIG`)
+
+```typescript
+CACHE_CONFIG.vndbCacheDuration // VNDB 缓存时长(毫秒)
+CACHE_CONFIG.searchCacheDuration // 搜索结果缓存时长(毫秒)
+CACHE_CONFIG.imageCacheDuration // 图片缓存时长(毫秒)
+CACHE_CONFIG.maxCacheSize // 最大缓存数量
+```
+
+### 6. UI 配置 (`UI_CONFIG`)
+
+```typescript
+UI_CONFIG.themePrimary // 主题主色调
+UI_CONFIG.themeAccent // 主题强调色
+UI_CONFIG.toastDuration // Toast 通知默认时长(毫秒)
+UI_CONFIG.scrollOffset // 滚动偏移量(像素)
+UI_CONFIG.scrollTopThreshold // 回到顶部按钮显示阈值(像素)
+```
+
+### 7. 第三方服务 (`THIRD_PARTY_CONFIG`)
+
+```typescript
+THIRD_PARTY_CONFIG.artalkServer // Artalk 服务器地址
+THIRD_PARTY_CONFIG.artalkSite // Artalk 站点名称
+THIRD_PARTY_CONFIG.busuanziEnabled // 不蒜子统计
+```
+
+### 8. 性能配置 (`PERFORMANCE_CONFIG`)
+
+```typescript
+PERFORMANCE_CONFIG.quicklinkDelay // Quicklink 预加载延迟(毫秒)
+PERFORMANCE_CONFIG.quicklinkLimit // Quicklink 预加载限制
+PERFORMANCE_CONFIG.statusCheckInterval // 状态检查间隔(毫秒)
+PERFORMANCE_CONFIG.statusCheckTimeout // 状态检查超时(毫秒)
+```
+
+### 9. 开发配置 (`DEV_CONFIG`)
+
+```typescript
+DEV_CONFIG.port // 开发服务器端口
+DEV_CONFIG.hmr // 热更新
+DEV_CONFIG.sourcemap // Source Map
+DEV_CONFIG.isDev // 是否开发环境
+DEV_CONFIG.isProd // 是否生产环境
+DEV_CONFIG.mode // 运行模式
+```
+
+## 实际使用示例
+
+### 示例 1:在 Store 中使用
+
+```typescript
+// src/stores/cache.ts
+import { CACHE_CONFIG } from '@/config'
+
+export const useCacheStore = defineStore('cache', () => {
+ const vndbCacheDuration = ref(CACHE_CONFIG.vndbCacheDuration)
+ const searchCacheDuration = ref(CACHE_CONFIG.searchCacheDuration)
+ const maxCacheSize = ref(CACHE_CONFIG.maxCacheSize)
+
+ // ...
+})
+```
+
+### 示例 2:在组件中使用
+
+```vue
+
+```
+
+### 示例 3:在 API 调用中使用
+
+```typescript
+// src/api/search.ts
+import { API_CONFIG } from '@/config'
+
+export async function searchGame(query: string) {
+ const response = await fetch(`${API_CONFIG.defaultApiUrl}/search`, {
+ method: 'POST',
+ body: JSON.stringify({ query }),
+ })
+ return response.json()
+}
+```
+
+### 示例 4:条件渲染
+
+```vue
+
+
+
+
+
+```
+
+## 环境区分
+
+Vite 支持多环境配置:
+
+- `.env` - 所有环境加载
+- `.env.local` - 所有环境加载,但会被 git 忽略
+- `.env.development` - 开发环境
+- `.env.production` - 生产环境
+
+优先级:`.env.[mode].local` > `.env.[mode]` > `.env.local` > `.env`
+
+## 注意事项
+
+1. **环境变量必须以 `VITE_` 开头**才能在客户端代码中访问
+2. **修改 .env 后需要重启开发服务器**
+3. **不要在 .env 中存储敏感信息**(如密钥、密码)
+4. **使用配置对象而不是直接访问环境变量**,获得更好的类型支持
+5. **生产环境的配置**应该通过构建工具或部署平台设置
+
+## 类型安全
+
+所有配置都有完整的 TypeScript 类型支持:
+
+```typescript
+import type { AppConfig } from '@/config'
+
+// 获取完整配置的类型
+const config: AppConfig = CONFIG
+
+// 自动补全和类型检查
+config.api.defaultApiUrl // ✅ 类型安全
+config.api.invalidKey // ❌ 编译错误
+```
+
+## 调试
+
+开发环境下,配置会自动打印到控制台:
+
+```javascript
+// 打开浏览器控制台查看
+📦 Application Config: {
+ api: {...},
+ app: {...},
+ features: {...},
+ ...
+}
+```
+
+可以通过 `VITE_ENABLE_DEV_LOGS=false` 关闭此功能。
+
diff --git a/docs/ENV_GUIDE.md b/docs/ENV_GUIDE.md
new file mode 100644
index 0000000..0681c80
--- /dev/null
+++ b/docs/ENV_GUIDE.md
@@ -0,0 +1,218 @@
+# 环境变量配置指南
+
+SearchGal Frontend 使用环境变量来管理各种配置项,实现开发和生产环境的分离。
+
+## 文件说明
+
+- `.env` - 所有环境的默认配置
+- `.env.development` - 开发环境特定配置
+- `.env.production` - 生产环境特定配置
+- `.env.example` - 配置模板文件(供参考)
+
+## 快速开始
+
+1. 复制示例文件:
+```bash
+cp .env.example .env
+```
+
+2. 根据需要修改 `.env` 文件中的配置
+
+3. 启动开发服务器:
+```bash
+pnpm dev
+```
+
+## 配置项说明
+
+### 应用信息
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_APP_TITLE` | 应用标题 | SearchGal - Galgame 聚合搜索 |
+| `VITE_APP_DESCRIPTION` | 应用描述 | 多平台 Galgame 资源聚合搜索引擎 |
+| `VITE_APP_VERSION` | 应用版本 | 1.0.0 |
+
+### API 配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_API_BASE_URL` | 搜索 API 地址 | https://cfapi.searchgal.homes |
+| `VITE_API_TIMEOUT` | API 超时时间(毫秒) | 30000 |
+| `VITE_TRANSLATE_API_URL` | 翻译 API 地址 | https://translate.searchgal.homes |
+| `VITE_VNDB_API_URL` | VNDB API 地址 | https://api.vndb.org/kana/v1 |
+
+### 外部服务
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_STATUS_URL` | 状态检查 URL | https://status.searchgal.homes |
+| `VITE_ARTALK_SERVER` | Artalk 评论服务器 | https://artalk.saop.cc |
+| `VITE_IMAGE_API_URL` | 随机图片 API | https://api.illlights.com/v1/img |
+
+### 网站信息
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_SITE_URL` | 网站 URL | https://searchgal.homes |
+| `VITE_SITE_NAME` | 网站名称 | SearchGal |
+| `VITE_GITHUB_URL` | GitHub 仓库 | https://github.com/Moe-Sakura/frontend |
+
+### 功能开关
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_ENABLE_COMMENTS` | 启用评论功能 | true |
+| `VITE_ENABLE_VNDB` | 启用 VNDB 集成 | true |
+| `VITE_ENABLE_AI_TRANSLATE` | 启用 AI 翻译 | true |
+| `VITE_ENABLE_PWA` | 启用 PWA 功能 | true |
+| `VITE_ENABLE_ANALYTICS` | 启用统计分析 | false |
+
+### 搜索配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_SEARCH_COOLDOWN` | 搜索冷却时间(毫秒) | 30000 |
+| `VITE_DEFAULT_RESULTS_PER_PAGE` | 默认每页结果数 | 10 |
+| `VITE_LOAD_MORE_COUNT` | 加载更多数量 | 20 |
+| `VITE_MAX_SEARCH_HISTORY` | 最大历史记录数 | 50 |
+
+### 缓存配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_CACHE_VNDB_DURATION` | VNDB 缓存时长(毫秒) | 1800000 (30分钟) |
+| `VITE_CACHE_SEARCH_DURATION` | 搜索缓存时长(毫秒) | 600000 (10分钟) |
+| `VITE_CACHE_IMAGE_DURATION` | 图片缓存时长(毫秒) | 3600000 (60分钟) |
+| `VITE_MAX_CACHE_SIZE` | 最大缓存项数 | 100 |
+
+### 主题配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_THEME_PRIMARY` | 主色调 | #ff1493 |
+| `VITE_THEME_ACCENT` | 强调色 | #d946ef |
+| `VITE_THEME_BACKGROUND_LIGHT` | 浅色背景 | #fff5fa |
+| `VITE_THEME_BACKGROUND_DARK` | 深色背景 | #1e293b |
+
+### 性能配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_QUICKLINK_DELAY` | Quicklink 延迟(毫秒) | 500 |
+| `VITE_QUICKLINK_LIMIT` | Quicklink 限制数 | 10 |
+| `VITE_LAZY_LOAD_THRESHOLD` | 懒加载阈值 | 0.5 |
+
+### 开发配置
+
+| 变量名 | 说明 | 默认值 |
+|--------|------|--------|
+| `VITE_ENABLE_DEBUG` | 启用调试模式 | false |
+| `VITE_ENABLE_MOCK` | 启用 Mock 数据 | false |
+
+## 使用方法
+
+### 1. 在代码中使用配置
+
+```typescript
+import { config } from '@/config'
+
+// 使用 API 地址
+const apiUrl = config.api.baseUrl
+
+// 检查功能开关
+if (config.features.comments) {
+ // 启用评论功能
+}
+
+// 使用搜索配置
+const cooldown = config.search.cooldown
+```
+
+### 2. 使用工具函数
+
+```typescript
+import { devLog, devWarn, devError, isDev, isProd } from '@/config'
+
+// 开发环境日志(只在 VITE_ENABLE_DEBUG=true 时显示)
+devLog('Debug message')
+devWarn('Warning message')
+devError('Error message')
+
+// 环境判断
+if (isDev) {
+ console.log('Running in development mode')
+}
+
+if (isProd) {
+ console.log('Running in production mode')
+}
+```
+
+### 3. 直接访问环境变量
+
+```typescript
+// 不推荐:直接访问(无类型安全)
+const apiUrl = import.meta.env.VITE_API_BASE_URL
+
+// 推荐:通过 config 对象访问(有类型安全)
+const apiUrl = config.api.baseUrl
+```
+
+## 环境变量优先级
+
+Vite 环境变量加载优先级(从高到低):
+
+1. `.env.[mode].local` (如 `.env.development.local`)
+2. `.env.[mode]` (如 `.env.development`)
+3. `.env.local`
+4. `.env`
+
+**注意**:`.local` 文件会被 `.gitignore` 忽略,不会提交到仓库。
+
+## 本地开发配置
+
+如果需要本地特定配置,创建 `.env.local` 文件:
+
+```bash
+# .env.local (不会被提交到 Git)
+VITE_API_BASE_URL=http://localhost:8787
+VITE_ENABLE_DEBUG=true
+```
+
+## 生产环境配置
+
+在 CI/CD 或服务器上设置环境变量,或使用 `.env.production` 文件。
+
+## 注意事项
+
+1. **只有 `VITE_` 前缀的变量会被暴露到客户端代码**
+2. **不要在环境变量中存储敏感信息**(如密钥、密码)
+3. **修改环境变量后需要重启开发服务器**
+4. **`.env.local` 文件不会被提交到仓库**
+
+## 故障排查
+
+### 环境变量没有生效
+
+1. 检查变量名是否以 `VITE_` 开头
+2. 重启开发服务器 (`pnpm dev`)
+3. 检查 `.env` 文件语法是否正确
+4. 使用 `console.log(config)` 查看加载的配置
+
+### 类型错误
+
+确保 `src/vite-env.d.ts` 文件存在并包含正确的类型定义。
+
+## 相关文件
+
+- `src/config/index.ts` - 配置工具类
+- `src/vite-env.d.ts` - TypeScript 类型定义
+- `.env` - 默认配置文件
+- `.env.example` - 配置模板
+
+## 更多信息
+
+- [Vite 环境变量文档](https://vitejs.dev/guide/env-and-mode.html)
+- [SearchGal 项目文档](./README.md)
+
diff --git a/docs/ENV_USAGE_EXAMPLES.md b/docs/ENV_USAGE_EXAMPLES.md
new file mode 100644
index 0000000..b63d8a1
--- /dev/null
+++ b/docs/ENV_USAGE_EXAMPLES.md
@@ -0,0 +1,271 @@
+# 环境变量使用示例
+
+## 迁移现有代码到使用环境变量
+
+### 1. API 调用
+
+**之前(硬编码):**
+```typescript
+const response = await fetch('https://cfapi.searchgal.homes/search')
+```
+
+**之后(使用配置):**
+```typescript
+import { config } from '@/config'
+
+const response = await fetch(`${config.api.baseUrl}/search`)
+```
+
+### 2. 搜索冷却时间
+
+**之前:**
+```typescript
+const COOLDOWN_MS = 30 * 1000
+```
+
+**之后:**
+```typescript
+import { config } from '@/config'
+
+const cooldown = config.search.cooldown
+```
+
+### 3. Store 初始化
+
+**在 stores/cache.ts 中:**
+```typescript
+import { config } from '@/config'
+
+export const useCacheStore = defineStore('cache', () => {
+ const vndbCacheDuration = ref(config.cache.vndbDuration)
+ const searchCacheDuration = ref(config.cache.searchDuration)
+ const maxCacheSize = ref(config.cache.maxSize)
+ // ...
+})
+```
+
+**在 stores/history.ts 中:**
+```typescript
+import { config } from '@/config'
+
+export const useHistoryStore = defineStore('history', () => {
+ const maxHistoryItems = ref(config.search.maxSearchHistory)
+ // ...
+})
+```
+
+**在 stores/search.ts 中:**
+```typescript
+import { config } from '@/config'
+
+export const useSearchStore = defineStore('search', () => {
+ const searchDisabled = computed(() => {
+ const now = Date.now()
+ return isSearching.value || (now - lastSearchTime.value < config.search.cooldown)
+ })
+ // ...
+})
+```
+
+### 4. Artalk 评论系统
+
+**在 CommentsModal.vue 中:**
+```typescript
+import { config } from '@/config'
+
+function initArtalk() {
+ if (!config.features.comments) {
+ return // 如果评论功能被禁用,不初始化
+ }
+
+ artalkInstance = Artalk.init({
+ el: '#Comments',
+ pageKey: config.site.url,
+ pageTitle: config.app.title,
+ server: config.services.artalkServer,
+ site: config.site.name,
+ darkMode: 'auto',
+ })
+}
+```
+
+### 5. Quicklink 配置
+
+**在 main.ts 中:**
+```typescript
+import { listen } from 'quicklink'
+import { config } from '@/config'
+
+window.addEventListener('load', () => {
+ listen({
+ delay: config.performance.quicklinkDelay,
+ limit: config.performance.quicklinkLimit,
+ ignores: [/\/api\//, /artalk/],
+ })
+})
+```
+
+### 6. 状态检查
+
+**在 SearchHeader.vue 中:**
+```typescript
+import { config } from '@/config'
+
+async function checkStatus() {
+ try {
+ const controller = new window.AbortController()
+ const timeoutId = setTimeout(() => controller.abort(), 5000)
+
+ await fetch(config.services.statusUrl, {
+ method: 'HEAD',
+ mode: 'no-cors',
+ signal: controller.signal,
+ })
+
+ clearTimeout(timeoutId)
+ statusOnline.value = true
+ } catch (_error) {
+ statusOnline.value = false
+ }
+}
+```
+
+### 7. 随机背景图片
+
+**在 App.vue 中:**
+```typescript
+import { config } from '@/config'
+
+async function loadRandomImage() {
+ try {
+ const timestamp = Date.now()
+ const imageUrl = `${config.services.imageApiUrl}?t=${timestamp}`
+ // ...
+ } catch (error) {
+ // ...
+ }
+}
+```
+
+### 8. 调试日志
+
+**使用工具函数:**
+```typescript
+import { devLog, devWarn, devError } from '@/config'
+
+// 这些日志只在开发环境且 VITE_ENABLE_DEBUG=true 时显示
+devLog('Fetching data from API...')
+devWarn('API response is slow')
+devError('API request failed')
+```
+
+### 9. 功能开关
+
+**条件渲染:**
+```vue
+
+
+
+
+
+
+
+
+
+```
+
+### 10. 主题颜色
+
+**使用环境变量定义的颜色:**
+```typescript
+import { config } from '@/config'
+
+// 动态设置 CSS 变量
+document.documentElement.style.setProperty('--theme-primary', config.theme.primary)
+document.documentElement.style.setProperty('--theme-accent', config.theme.accent)
+```
+
+## 完整示例:API 工具类
+
+```typescript
+// src/utils/request.ts
+import { config, devLog, devError } from '@/config'
+
+class ApiClient {
+ private baseUrl: string
+ private timeout: number
+
+ constructor() {
+ this.baseUrl = config.api.baseUrl
+ this.timeout = config.api.timeout
+ }
+
+ async request(endpoint: string, options: RequestInit = {}) {
+ const url = `${this.baseUrl}${endpoint}`
+
+ devLog('API Request:', url, options)
+
+ const controller = new AbortController()
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout)
+
+ try {
+ const response = await fetch(url, {
+ ...options,
+ signal: controller.signal,
+ })
+
+ clearTimeout(timeoutId)
+
+ devLog('API Response:', response.status, response.statusText)
+
+ return response
+ } catch (error) {
+ clearTimeout(timeoutId)
+ devError('API Error:', error)
+ throw error
+ }
+ }
+}
+
+export const apiClient = new ApiClient()
+```
+
+## 环境特定逻辑
+
+```typescript
+import { isDev, isProd, config } from '@/config'
+
+// 开发环境特定逻辑
+if (isDev) {
+ // 启用 Vue DevTools
+ if (window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
+ window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = app
+ }
+}
+
+// 生产环境特定逻辑
+if (isProd && config.features.analytics) {
+ // 初始化统计工具
+ initAnalytics()
+}
+
+// Mock 数据
+if (config.dev.mock) {
+ import('./mocks').then(({ setupMocks }) => {
+ setupMocks()
+ })
+}
+```
+
diff --git a/docs/PINIA_GUIDE.md b/docs/PINIA_GUIDE.md
new file mode 100644
index 0000000..1ec873a
--- /dev/null
+++ b/docs/PINIA_GUIDE.md
@@ -0,0 +1,276 @@
+# Pinia Store 使用指南
+
+SearchGal 使用 Pinia 进行状态管理,已充分优化和模块化。
+
+## Store 模块
+
+### 1. Search Store (`useSearchStore`)
+**用途**:管理搜索相关的状态和逻辑
+
+```typescript
+import { useSearchStore } from '@/stores'
+
+const searchStore = useSearchStore()
+
+// 状态
+searchStore.searchQuery // 搜索关键词
+searchStore.searchMode // 搜索模式 ('game' | 'patch')
+searchStore.platformResults // 平台搜索结果
+searchStore.vndbInfo // VNDB 游戏信息
+searchStore.isSearching // 是否正在搜索
+searchStore.searchProgress // 搜索进度
+
+// 计算属性
+searchStore.hasResults // 是否有搜索结果
+searchStore.isVndbMode // 是否为 VNDB 模式
+searchStore.searchDisabled // 是否禁用搜索(冷却时间)
+
+// 方法
+searchStore.setSearchQuery('关键词')
+searchStore.setSearchMode('game')
+searchStore.startSearch()
+searchStore.endSearch()
+searchStore.setPlatformResult('platform', data)
+searchStore.loadMoreResults('platform', 20)
+searchStore.clearResults()
+```
+
+### 2. UI Store (`useUIStore`)
+**用途**:管理UI相关状态(主题、模态框、通知等)
+
+```typescript
+import { useUIStore } from '@/stores'
+
+const uiStore = useUIStore()
+
+// 主题
+uiStore.isDarkMode
+uiStore.toggleDarkMode()
+uiStore.setDarkMode(true)
+
+// 模态框
+uiStore.isCommentsModalOpen
+uiStore.isVndbPanelOpen
+uiStore.isSettingsModalOpen
+uiStore.toggleCommentsModal()
+uiStore.closeAllModals()
+
+// Toast 通知
+uiStore.showToast('success', '操作成功!', 3000)
+uiStore.showToast('error', '操作失败!')
+
+// 浮动按钮
+uiStore.showScrollToTop
+uiStore.showPlatformNav
+uiStore.togglePlatformNav()
+
+// 加载状态
+uiStore.setLoading(true, '加载中...')
+uiStore.setLoading(false)
+```
+
+### 3. Settings Store (`useSettingsStore`)
+**用途**:管理用户设置
+
+```typescript
+import { useSettingsStore } from '@/stores'
+
+const settingsStore = useSettingsStore()
+
+// 访问设置
+settingsStore.settings.customApi
+settingsStore.settings.autoLoadMore
+settingsStore.settings.resultsPerPage
+
+// 更新单个设置
+settingsStore.updateSetting('resultsPerPage', 20)
+
+// 批量更新
+settingsStore.updateSettings({
+ customApi: 'https://api.example.com',
+ autoLoadMore: true,
+})
+
+// 重置设置
+settingsStore.resetSettings()
+
+// 导入导出
+const json = settingsStore.exportSettings()
+settingsStore.importSettings(json)
+```
+
+### 4. History Store (`useHistoryStore`)
+**用途**:管理搜索历史
+
+```typescript
+import { useHistoryStore } from '@/stores'
+
+const historyStore = useHistoryStore()
+
+// 访问历史
+historyStore.searchHistory // 所有历史
+historyStore.recentHistory // 最近10条
+historyStore.popularQueries // 热门查询
+
+// 添加历史
+historyStore.addHistory({
+ query: '关键词',
+ mode: 'game',
+ resultCount: 10,
+})
+
+// 删除历史
+historyStore.removeHistory(0)
+historyStore.removeHistoryByQuery('关键词')
+historyStore.clearHistory()
+
+// 搜索历史
+const results = historyStore.searchInHistory('关键词')
+
+// 统计信息
+const stats = historyStore.getHistoryStats()
+```
+
+### 5. Cache Store (`useCacheStore`)
+**用途**:管理缓存数据
+
+```typescript
+import { useCacheStore } from '@/stores'
+
+const cacheStore = useCacheStore()
+
+// VNDB 缓存
+cacheStore.cacheVndbInfo('query', vndbData)
+const cached = cacheStore.getVndbInfo('query')
+const hasCache = cacheStore.hasVndbCache('query')
+
+// 搜索结果缓存
+cacheStore.cacheSearchResults('query', 'game', results)
+const results = cacheStore.getSearchResults('query', 'game')
+
+// 清理缓存
+cacheStore.clearVndbCache()
+cacheStore.clearSearchCache()
+cacheStore.clearAllCache()
+cacheStore.cleanExpiredCache() // 清理过期缓存
+
+// 缓存统计
+const stats = cacheStore.getCacheStats()
+```
+
+## Store 插件
+
+### 开发环境日志
+在开发环境自动记录所有 action 调用和状态变化
+
+### 性能监控
+自动记录每个 action 的执行时间和调用次数
+
+```typescript
+// 获取性能统计
+const stats = searchStore.getPerformanceStats()
+console.log(stats)
+// {
+// startSearch: { calls: 5, avgDuration: '12.50ms', totalDuration: '62.50ms' },
+// ...
+// }
+```
+
+### 错误处理
+自动捕获和记录 store 中的错误
+
+## 最佳实践
+
+### 1. 组件中使用 Store
+```vue
+
+```
+
+### 2. Store 之间通信
+```typescript
+// 在 searchStore 中使用 historyStore
+const historyStore = useHistoryStore()
+const cacheStore = useCacheStore()
+
+// 搜索完成后添加历史
+historyStore.addHistory({...})
+
+// 使用缓存
+const cached = cacheStore.getVndbInfo(query)
+if (cached) {
+ // 使用缓存数据
+}
+```
+
+### 3. 响应式更新
+```typescript
+// ✅ 正确:使用 ref 或 computed
+const searchQuery = computed(() => searchStore.searchQuery)
+
+// ❌ 错误:直接解构会失去响应性
+const { searchQuery } = searchStore
+
+// ✅ 正确:使用 storeToRefs
+import { storeToRefs } from 'pinia'
+const { searchQuery } = storeToRefs(searchStore)
+```
+
+### 4. 性能优化
+```typescript
+// 使用缓存避免重复请求
+function searchGame(query: string) {
+ // 检查缓存
+ const cached = cacheStore.getSearchResults(query, 'game')
+ if (cached) {
+ searchStore.setPlatformResult('platform', cached)
+ return
+ }
+
+ // 执行搜索并缓存结果
+ // ...
+}
+```
+
+## 调试技巧
+
+### 1. Vue DevTools
+安装 Vue DevTools 扩展,可以实时查看所有 store 的状态
+
+### 2. 控制台日志
+开发环境会自动记录所有 action 和状态变化
+
+### 3. 性能分析
+```javascript
+// 在控制台查看性能统计
+console.log(useSearchStore().getPerformanceStats())
+console.log(useCacheStore().getCacheStats())
+console.log(useHistoryStore().getHistoryStats())
+```
+
+### 4. 手动清理
+```javascript
+// 清除所有缓存
+useCacheStore().clearAllCache()
+
+// 清除历史记录
+useHistoryStore().clearHistory()
+
+// 重置设置
+useSettingsStore().resetSettings()
+```
+
diff --git a/env.d.ts b/env.d.ts
index 6800fc0..af85660 100644
--- a/env.d.ts
+++ b/env.d.ts
@@ -20,3 +20,71 @@ interface Window {
}
}
}
+
+// 环境变量类型定义
+interface ImportMetaEnv {
+ // API 配置
+ readonly VITE_DEFAULT_API_URL: string
+ readonly VITE_VNDB_API_URL: string
+ readonly VITE_TRANSLATE_API_URL: string
+ readonly VITE_STATUS_API_URL: string
+ readonly VITE_RANDOM_IMAGE_API: string
+
+ // 应用配置
+ readonly VITE_APP_NAME: string
+ readonly VITE_APP_TITLE: string
+ readonly VITE_APP_DESCRIPTION: string
+ readonly VITE_APP_URL: string
+
+ // 功能开关
+ readonly VITE_ENABLE_PWA: string
+ readonly VITE_ENABLE_SW: string
+ readonly VITE_ENABLE_COMMENTS: string
+ readonly VITE_ENABLE_VNDB: string
+ readonly VITE_ENABLE_TRANSLATE: string
+ readonly VITE_ENABLE_HISTORY: string
+ readonly VITE_ENABLE_CACHE: string
+ readonly VITE_ENABLE_PERFORMANCE: string
+ readonly VITE_ENABLE_DEV_LOGS: string
+
+ // 搜索配置
+ readonly VITE_DEFAULT_SEARCH_MODE: string
+ readonly VITE_SEARCH_COOLDOWN: string
+ readonly VITE_DEFAULT_RESULTS_PER_PAGE: string
+ readonly VITE_LOAD_MORE_COUNT: string
+ readonly VITE_MAX_HISTORY_ITEMS: string
+
+ // 缓存配置
+ readonly VITE_VNDB_CACHE_DURATION: string
+ readonly VITE_SEARCH_CACHE_DURATION: string
+ readonly VITE_IMAGE_CACHE_DURATION: string
+ readonly VITE_MAX_CACHE_SIZE: string
+
+ // UI 配置
+ readonly VITE_THEME_PRIMARY: string
+ readonly VITE_THEME_ACCENT: string
+ readonly VITE_TOAST_DURATION: string
+ readonly VITE_SCROLL_OFFSET: string
+ readonly VITE_SCROLL_TOP_THRESHOLD: string
+
+ // 第三方服务
+ readonly VITE_ARTALK_SERVER: string
+ readonly VITE_ARTALK_SITE: string
+ readonly VITE_BUSUANZI_ENABLED: string
+
+ // 性能配置
+ readonly VITE_QUICKLINK_DELAY: string
+ readonly VITE_QUICKLINK_LIMIT: string
+ readonly VITE_STATUS_CHECK_INTERVAL: string
+ readonly VITE_STATUS_CHECK_TIMEOUT: string
+
+ // 开发配置
+ readonly VITE_DEV_PORT: string
+ readonly VITE_HMR: string
+ readonly VITE_SOURCEMAP: string
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv
+}
+
diff --git a/index.html b/index.html
index 44f273e..32700b8 100644
--- a/index.html
+++ b/index.html
@@ -50,6 +50,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index f3fb5a1..03a9521 100644
--- a/package.json
+++ b/package.json
@@ -27,11 +27,12 @@
},
"dependencies": {
"@fancyapps/ui": "^6.1.5",
- "@fortawesome/fontawesome-free": "^7.1.0",
"artalk": "^2.9.1",
+ "lazysizes": "^5.3.2",
"lucide-vue-next": "^0.555.0",
"pace-js": "^1.2.4",
"pinia": "^3.0.4",
+ "quicklink": "^3.0.1",
"vue": "^3.5.24"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c03f507..23a1252 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,12 +11,12 @@ importers:
'@fancyapps/ui':
specifier: ^6.1.5
version: 6.1.5
- '@fortawesome/fontawesome-free':
- specifier: ^7.1.0
- version: 7.1.0
artalk:
specifier: ^2.9.1
version: 2.9.1(marked@14.1.4)
+ lazysizes:
+ specifier: ^5.3.2
+ version: 5.3.2
lucide-vue-next:
specifier: ^0.555.0
version: 0.555.0(vue@3.5.24(typescript@5.9.3))
@@ -26,6 +26,9 @@ importers:
pinia:
specifier: ^3.0.4
version: 3.0.4(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))
+ quicklink:
+ specifier: ^3.0.1
+ version: 3.0.1
vue:
specifier: ^3.5.24
version: 3.5.24(typescript@5.9.3)
@@ -286,10 +289,6 @@ packages:
'@fancyapps/ui@6.1.5':
resolution: {integrity: sha512-uFNm+rlrVMD8vqnthVC0l9ME+V8HRUma5LLpkR/2DACUNKSpE8qppcns0ZITcODdUmV/dGxPHTnymihohp2/Og==}
- '@fortawesome/fontawesome-free@7.1.0':
- resolution: {integrity: sha512-+WxNld5ZCJHvPQCr/GnzCTVREyStrAJjisUPtUxG5ngDA8TMlPnKp6dddlTpai4+1GNmltAeuk1hJEkBohwZYA==}
- engines: {node: '>=6'}
-
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -978,6 +977,9 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ lazysizes@5.3.2:
+ resolution: {integrity: sha512-22UzWP+Vedi/sMeOr8O7FWimRVtiNJV2HCa+V8+peZOw6QbswN9k58VUhd7i6iK5bw5QkYrF01LJbeJe0PV8jg==}
+
levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
@@ -1179,6 +1181,21 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ quicklink@3.0.1:
+ resolution: {integrity: sha512-sAMEpcCUCzjet214qVCm1hzxeF0YLo4wyphkIifeemmofk1vMrc5Sg/iNH32SKAIXqYvO6SPZgEP8obi9Ait9g==}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+ react-dom: ^16.8.0 || ^17 || ^18 || ^19
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
+ regexparam@1.3.0:
+ resolution: {integrity: sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==}
+ engines: {node: '>=6'}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -1195,6 +1212,10 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ route-manifest@1.0.0:
+ resolution: {integrity: sha512-qn0xJr4nnF4caj0erOLLAHYiNyzqhzpUbgDQcEHrmBoG4sWCDLnIXLH7VccNSxe9cWgbP2Kw/OjME+eH3CeRSA==}
+ engines: {node: '>= 6'}
+
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -1250,6 +1271,10 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ throttles@1.0.1:
+ resolution: {integrity: sha512-fab7Xg+zELr9KOv4fkaBoe/b3L0GMGLd0IBSCn16GoE/Qx6/OfCr1eGNyEcDU2pUA79qQfZ8kPQWlRuok4YwTw==}
+ engines: {node: '>=6'}
+
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
@@ -1510,8 +1535,6 @@ snapshots:
'@fancyapps/ui@6.1.5': {}
- '@fortawesome/fontawesome-free@7.1.0': {}
-
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -2209,6 +2232,8 @@ snapshots:
dependencies:
json-buffer: 3.0.1
+ lazysizes@5.3.2: {}
+
levn@0.4.1:
dependencies:
prelude-ls: 1.2.1
@@ -2369,6 +2394,13 @@ snapshots:
queue-microtask@1.2.3: {}
+ quicklink@3.0.1:
+ dependencies:
+ route-manifest: 1.0.0
+ throttles: 1.0.1
+
+ regexparam@1.3.0: {}
+
resolve-from@4.0.0: {}
reusify@1.1.0: {}
@@ -2403,6 +2435,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.53.2
fsevents: 2.3.3
+ route-manifest@1.0.0:
+ dependencies:
+ regexparam: 1.3.0
+
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -2450,6 +2486,8 @@ snapshots:
source-map-support: 0.5.21
optional: true
+ throttles@1.0.1: {}
+
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
diff --git a/public/browserconfig.xml b/public/browserconfig.xml
new file mode 100644
index 0000000..5e5f277
--- /dev/null
+++ b/public/browserconfig.xml
@@ -0,0 +1,11 @@
+
+