-
- {screenshots.map((src, i) => (
-
-

-
- ))}
-
- {screenshots.length > 1 && (
-
- {screenshots.map((_, i) => (
-
+ >
);
}
diff --git a/src/components/StatsBar.tsx b/src/components/StatsBar.tsx
index c00aac0..534fd25 100644
--- a/src/components/StatsBar.tsx
+++ b/src/components/StatsBar.tsx
@@ -5,13 +5,11 @@ export default function StatsBar() {
const { t } = useI18n();
const projects = siteData.projects;
- const totalStars = projects.reduce((sum, p) => sum + p.stars, 0);
const uniqueTechStacks = new Set(projects.flatMap((p) => p.techStack)).size;
const uniquePlatforms = new Set(projects.flatMap((p) => p.platforms)).size;
const stats = [
{ id: 'projects', value: projects.length, label: t('stats.projects') },
- { id: 'stars', value: totalStars, label: t('stats.stars') },
{ id: 'techStack', value: uniqueTechStacks, label: t('stats.techStack') },
{ id: 'platforms', value: uniquePlatforms, label: t('stats.platforms') },
];
diff --git a/src/data/i18n/en.yaml b/src/data/i18n/en.yaml
index f3ac4f8..8b6b6b9 100644
--- a/src/data/i18n/en.yaml
+++ b/src/data/i18n/en.yaml
@@ -8,7 +8,6 @@ hero.cta.github: 'Visit GitHub'
hero.cta.download: 'Download Software'
hero.cta.docs: 'View Docs'
stats.projects: 'Open Source Projects'
-stats.stars: 'GitHub Stars'
stats.techStack: 'Tech Stacks'
stats.platforms: 'Platforms'
featured.title: 'Featured Projects'
@@ -30,7 +29,6 @@ projects.filter.tech: 'Tech Stack'
projects.filter.platform: 'Platform'
projects.filter.status: 'Status'
projects.sort.updated: 'Recently Updated'
-projects.sort.stars: 'Most Stars'
projects.sort.name: 'By Name'
projects.noResults: 'No matching projects'
projects.search: 'Search project name, description, or tags...'
@@ -49,6 +47,7 @@ detail.platforms: 'Platforms'
detail.status: 'Status'
detail.lastUpdate: 'Last Updated'
detail.repo: 'GitHub Repo'
+detail.website: 'Website'
detail.docs: 'Online Docs'
detail.release: 'Download Release'
detail.installGuide: 'Installation Guide'
@@ -119,8 +118,6 @@ common.download: 'Download'
common.docs: 'Docs'
common.demo: 'Live Demo'
common.back: 'Back'
-common.stars: 'Stars'
-common.forks: 'Forks'
common.version: 'Version'
common.platform: 'Platform'
common.size: 'Size'
diff --git a/src/data/i18n/zh.yaml b/src/data/i18n/zh.yaml
index 6d0892a..5811828 100644
--- a/src/data/i18n/zh.yaml
+++ b/src/data/i18n/zh.yaml
@@ -8,7 +8,6 @@ hero.cta.github: '访问 GitHub'
hero.cta.download: '下载软件'
hero.cta.docs: '查看文档'
stats.projects: '开源项目'
-stats.stars: 'GitHub Stars'
stats.techStack: '技术栈'
stats.platforms: '支持平台'
featured.title: '重点项目'
@@ -30,7 +29,6 @@ projects.filter.tech: '技术栈'
projects.filter.platform: '平台'
projects.filter.status: '状态'
projects.sort.updated: '最近更新'
-projects.sort.stars: 'Star 最多'
projects.sort.name: '名称排序'
projects.noResults: '没有匹配的项目'
projects.search: '搜索项目名称、描述或标签...'
@@ -49,6 +47,7 @@ detail.platforms: '支持平台'
detail.status: '开发状态'
detail.lastUpdate: '最后更新'
detail.repo: 'GitHub 仓库'
+detail.website: '官网'
detail.docs: '在线文档'
detail.release: '下载 Release'
detail.installGuide: '安装说明'
@@ -119,8 +118,6 @@ common.download: '下载'
common.docs: '文档'
common.demo: '在线演示'
common.back: '返回'
-common.stars: 'Stars'
-common.forks: 'Forks'
common.version: '版本'
common.platform: '平台'
common.size: '大小'
diff --git a/src/data/projects/billddesk.yaml b/src/data/projects/billddesk.yaml
index bb37a65..4ed105f 100644
--- a/src/data/projects/billddesk.yaml
+++ b/src/data/projects/billddesk.yaml
@@ -44,13 +44,12 @@ tags:
- 'WebRTC'
- 'Self-hosted'
icon: 'Monitor'
+logo: '/logos/billddesk.png'
repoUrl: 'https://github.com/shenjianZ/billddesk'
docsUrl: 'https://github.com/shenjianZ/billddesk#readme'
latestVersion: 'v0.8.0'
releaseDate: '2026-02-14'
license: 'Apache-2.0'
-stars: 45
-forks: 9
language: 'TypeScript'
lastUpdated: '2026-04-20'
recommended: false
diff --git a/src/data/projects/codex-manager.yaml b/src/data/projects/codex-manager.yaml
index 4db5950..d2cab10 100644
--- a/src/data/projects/codex-manager.yaml
+++ b/src/data/projects/codex-manager.yaml
@@ -45,13 +45,12 @@ tags:
- 'Account Management'
- 'Desktop'
icon: 'KeyRound'
+logo: '/logos/codex-manager.png'
repoUrl: 'https://github.com/shenjianZ/codex-manager'
docsUrl: 'https://github.com/shenjianZ/codex-manager#readme'
latestVersion: 'v0.1.0-beta'
releaseDate: '2026-04-28'
license: 'MIT'
-stars: 34
-forks: 2
language: 'Rust'
lastUpdated: '2026-05-05'
recommended: false
diff --git a/src/data/projects/devicedeck.yaml b/src/data/projects/devicedeck.yaml
index 5b5164a..a1138cc 100644
--- a/src/data/projects/devicedeck.yaml
+++ b/src/data/projects/devicedeck.yaml
@@ -49,13 +49,12 @@ tags:
- 'Scrcpy'
- 'Debug'
icon: 'Smartphone'
+logo: '/logos/devicedeck.png'
repoUrl: 'https://github.com/shenjianZ/devicedeck'
docsUrl: 'https://github.com/shenjianZ/devicedeck#readme'
latestVersion: 'v0.3.0'
releaseDate: '2026-04-20'
license: 'MIT'
-stars: 72
-forks: 6
language: 'Rust'
lastUpdated: '2026-05-12'
recommended: true
diff --git a/src/data/projects/news-classifier.yaml b/src/data/projects/news-classifier.yaml
index 5297335..d2d6fa5 100644
--- a/src/data/projects/news-classifier.yaml
+++ b/src/data/projects/news-classifier.yaml
@@ -45,13 +45,12 @@ tags:
- 'Classification'
- 'API'
icon: 'Brain'
+logo: '/logos/news-classifier.png'
repoUrl: 'https://github.com/shenjianZ/news-classifier'
docsUrl: 'https://github.com/shenjianZ/news-classifier#readme'
latestVersion: 'v0.1.0'
releaseDate: '2025-12-01'
license: 'MIT'
-stars: 23
-forks: 3
language: 'Python'
lastUpdated: '2026-03-15'
recommended: false
diff --git a/src/data/projects/quantanote.yaml b/src/data/projects/quantanote.yaml
index 97eb817..058dd31 100644
--- a/src/data/projects/quantanote.yaml
+++ b/src/data/projects/quantanote.yaml
@@ -4,15 +4,15 @@ displayName:
zh: 'QuantaNote'
en: 'QuantaNote'
slogan:
- zh: '本地优先的跨平台桌面笔记与知识管理工具'
- en: 'Local-first cross-platform desktop note & knowledge management tool'
+ zh: '本地优先的跨平台桌面笔记与知识管理工具 — Markdown 编辑、全文搜索、悬浮球快捷操作'
+ en: 'Local-first cross-platform desktop note & knowledge management — Markdown editing, full-text search, floating ball quick actions'
description:
- zh: 'QuantaNote 是一个基于 Tauri 2、Rust 和 React 构建的本地优先桌面笔记软件。面向需要离线使用、Markdown 编辑、资料归档、快速搜索和长期保存笔记的用户。相比传统云笔记,它更强调本地数据控制、轻量启动和跨平台桌面体验。'
- en: 'QuantaNote is a local-first desktop note-taking app built with Tauri 2, Rust, and React. Designed for users who need offline Markdown editing, knowledge archiving, fast search, and long-term note storage. Emphasizes local data control, lightweight startup, and cross-platform desktop experience.'
+ zh: 'QuantaNote 是一个基于 Tauri 2、Rust 和 React 构建的本地优先桌面笔记软件。支持 Markdown 编辑(Vditor IR 模式)、FTS5 全文搜索(含中文子串)、标签管理、版本历史 Diff 对比、附件预览、导入导出、自动备份、悬浮球快捷操作等功能。所有数据存储在本地 SQLite,强调数据主权和轻量跨平台体验。支持云同步(开发中)。'
+ en: 'QuantaNote is a local-first desktop note app built with Tauri 2, Rust, and React. Features include Markdown editing (Vditor IR mode), FTS5 full-text search with Chinese substring support, tag management, version history with diff comparison, attachment preview, import/export, auto backup, and floating ball quick actions. All data is stored in local SQLite, emphasizing data ownership and lightweight cross-platform experience. Cloud sync is under development.'
type:
- 'desktop'
- 'devtool'
-status: 'active'
+status: 'maintained'
platforms:
- 'windows'
- 'macos'
@@ -20,50 +20,63 @@ platforms:
techStack:
- 'Tauri 2'
- 'Rust'
- - 'React'
+ - 'React 19'
- 'TypeScript'
- - 'SQLite'
- - 'TailwindCSS'
+ - 'SQLite (rusqlite 0.35)'
+ - 'TailwindCSS 4'
+ - 'Vditor'
+ - 'Zustand'
+ - 'i18next'
features:
zh:
- - 'Markdown 编辑'
- - '本地 SQLite 存储'
- - '全文搜索'
- - '标签管理'
- - '附件预览'
- - '版本历史'
- - '导入导出'
- - '自动备份'
- - '主题切换'
- - '系统托盘'
+ - 'Markdown 编辑器(Vditor IR 模式)'
+ - '全文搜索(FTS5 + trigram 双引擎,支持中文子串)'
+ - '标签管理(CRUD + 多对多关联)'
+ - '命令面板(Ctrl+K 全局快速搜索)'
+ - '版本历史与 Diff 对比'
+ - '附件管理(图片/音频/视频/PDF 预览)'
+ - '数据导入导出(JSON / ZIP 可选)'
+ - '定时自动备份'
+ - '深色/浅色主题 + 自定义强调色'
+ - '系统托盘 + 开机自启动'
+ - '悬浮球快捷操作(径向菜单)'
+ - '快速笔记独立窗口'
+ - '中英文国际化'
- '云同步(开发中)'
en:
- - 'Markdown editing'
- - 'Local SQLite storage'
- - 'Full-text search'
- - 'Tag management'
- - 'Attachment preview'
- - 'Version history'
- - 'Import/export'
- - 'Auto backup'
- - 'Theme switching'
- - 'System tray'
+ - 'Markdown editor (Vditor IR mode)'
+ - 'Full-text search (FTS5 + trigram, Chinese substring)'
+ - 'Tag management (CRUD + many-to-many)'
+ - 'Command palette (Ctrl+K global search)'
+ - 'Version history with diff comparison'
+ - 'Attachment management (image/audio/video/PDF preview)'
+ - 'Import/Export (JSON / ZIP selectable)'
+ - 'Scheduled auto backup'
+ - 'Dark/Light theme + custom accent colors'
+ - 'System tray + auto-start on boot'
+ - 'Floating ball quick actions (radial menu)'
+ - 'Quick note standalone window'
+ - 'i18n (Chinese / English)'
- 'Cloud sync (WIP)'
tags:
- 'Markdown'
- 'Notes'
- 'Knowledge Management'
- 'Desktop'
+ - 'Notebook'
+ - 'Local-first'
+ - 'Tauri'
+ - 'Vditor'
icon: 'NotebookPen'
-repoUrl: 'https://github.com/shenjianZ/quantanote'
-docsUrl: 'https://github.com/shenjianZ/quantanote#readme'
-latestVersion: 'v0.2.0'
-releaseDate: '2026-04-15'
+logo: '/logos/quantanote.png'
+repoUrl: 'https://github.com/shenjianZ/QuantaNote'
+websiteUrl: 'https://shenjianz.github.io/QuantaNote/'
+docsUrl: 'https://quantanote-docs.shenjianl.cn/'
+latestVersion: 'v0.2.3'
+releaseDate: '2026-05-12'
license: 'MIT'
-stars: 128
-forks: 12
language: 'Rust'
-lastUpdated: '2026-05-10'
+lastUpdated: '2026-05-12'
recommended: true
featured: true
order: 1
@@ -71,23 +84,23 @@ color: '#3B82F6'
downloads:
- platform: 'Windows'
arch: 'x64'
- url: 'https://github.com/shenjianZ/quantanote/releases/download/v0.2.0/QuantaNote_0.2.0_x64-setup.exe'
- size: '22.6 MB'
+ url: 'https://file.shenjianl.cn/softwore/QuantaNote/v0.2.3/QuantaNote-v0.2.3-windows-x64.exe'
+ size: '9.6 MB'
sha256: ''
- platform: 'macOS'
arch: 'Apple Silicon'
- url: 'https://github.com/shenjianZ/quantanote/releases/download/v0.2.0/QuantaNote_0.2.0_aarch64.dmg'
- size: '18.3 MB'
+ url: 'https://file.shenjianl.cn/softwore/QuantaNote/v0.2.3/QuantaNote-v0.2.3-macos-aarch64.dmg'
+ size: '14.3 MB'
sha256: ''
- platform: 'macOS'
arch: 'Intel'
- url: 'https://github.com/shenjianZ/quantanote/releases/download/v0.2.0/QuantaNote_0.2.0_x64.dmg'
- size: '19.1 MB'
+ url: 'https://file.shenjianl.cn/softwore/QuantaNote/v0.2.3/QuantaNote-v0.2.3-macos-x64.dmg'
+ size: '14.7 MB'
sha256: ''
- platform: 'Linux'
arch: 'x64'
- url: 'https://github.com/shenjianZ/quantanote/releases/download/v0.2.0/QuantaNote_0.2.0_amd64.AppImage'
- size: '20.2 MB'
+ url: 'https://file.shenjianl.cn/softwore/QuantaNote/v0.2.3/QuantaNote-v0.2.3-linux-x64.AppImage'
+ size: '86.1 MB'
sha256: ''
roadmap:
done:
@@ -96,44 +109,136 @@ roadmap:
- '本地存储'
- '标签系统'
- '全文搜索'
+ - '版本历史与 Diff'
+ - '附件管理'
+ - '导入导出'
+ - '自动备份'
+ - '主题与自定义强调色'
+ - '系统托盘与开机自启'
+ - '账号管理'
+ - '悬浮球快捷操作'
+ - '快速笔记窗口'
doing:
- '云同步'
- '多端同步'
- - '账号管理'
planned:
- '插件系统'
- - 'MCP 接入'
- '移动端查看'
- 'AI 辅助写作'
changelog:
- - version: 'v0.2.0'
- date: '2026-04-15'
+ - version: 'v0.2.3'
+ date: '2026-05-12'
changes:
zh:
- - '新增账号管理模块'
- - '修复 Token 刷新竞态'
- - '优化同步状态显示'
- - '新增附件预览支持'
+ - '悬浮球功能:收起时球体、展开时径向菜单,支持快速笔记和搜索'
+ - '悬浮球设置项:透明度调节、窗口置顶、开关控制'
+ - '快速笔记独立窗口,支持 Markdown 编辑'
+ - '完整中英文国际化支持'
en:
- - 'Added account management'
- - 'Fixed token refresh race condition'
- - 'Improved sync status display'
- - 'Added attachment preview'
+ - 'Floating ball: radial menu for quick notes and search'
+ - 'Floating ball settings: opacity, always-on-top, toggle'
+ - 'Quick note standalone window with Markdown editing'
+ - 'Full Chinese/English i18n support'
+ - version: 'v0.2.2'
+ date: '2026-05-11'
+ changes:
+ zh:
+ - '修复更新包公钥配置被占位符覆盖导致签名校验失败'
+ - '更新关于页的更新错误提示'
+ en:
+ - 'Fixed updater public key config overridden by placeholder'
+ - 'Improved update error messages on About page'
+ - version: 'v0.2.1'
+ date: '2026-05-11'
+ changes:
+ zh:
+ - '升级 rusqlite 0.31→0.35、thiserror 1→2'
+ - '同步状态管理改用 Result 替代 unwrap'
+ - '新增密码长度、标签颜色等输入验证'
+ - '修复前端 TopBar 非 Tauri 环境报错'
+ - '编辑器搜索高亮改用 DOM API'
+ en:
+ - 'Upgraded rusqlite 0.31→0.35, thiserror 1→2'
+ - 'Sync state management uses Result instead of unwrap'
+ - 'Added input validation for password length, tag colors'
+ - 'Fixed TopBar errors in non-Tauri environment'
+ - 'Editor search highlight uses DOM API'
+ - version: 'v0.2.0'
+ date: '2026-05-05'
+ changes:
+ zh:
+ - '新增账号管理(个人资料、修改密码、删除账号)'
+ - '云同步增强:Token 刷新竞态修复、同步状态指示器'
+ - 'Docker 多阶段构建 + docker-compose 部署'
+ - '文档站自动部署到 GitHub Pages'
+ en:
+ - 'Account management (profile, password change, account deletion)'
+ - 'Cloud sync: token refresh race fix, sync status indicator'
+ - 'Docker multi-stage build + docker-compose deployment'
+ - 'Docs auto-deploy to GitHub Pages'
- version: 'v0.1.0'
- date: '2026-02-20'
+ date: '2026-05-02'
changes:
zh:
- '首个公开版本'
- - '基础笔记 CRUD'
- - 'Markdown 编辑器'
- - '本地 SQLite 存储'
- - '标签管理'
+ - 'Markdown 编辑器(Vditor IR 模式)'
+ - '全文搜索(FTS5 + trigram 双引擎)'
+ - '版本历史与 Diff 对比'
+ - '附件管理、导入导出、自动备份'
+ - '主题切换、系统托盘'
en:
- 'First public release'
- - 'Basic note CRUD'
- - 'Markdown editor'
- - 'Local SQLite storage'
- - 'Tag management'
+ - 'Markdown editor (Vditor IR mode)'
+ - 'Full-text search (FTS5 + trigram dual engine)'
+ - 'Version history with diff comparison'
+ - 'Attachments, import/export, auto backup'
+ - 'Theme switching, system tray'
architecture:
- zh: '前端 (React + TypeScript) → Tauri Commands → Rust 核心层 → SQLite 数据库 → 本地文件存储'
- en: 'Frontend (React + TypeScript) → Tauri Commands → Rust Core → SQLite Database → Local File Storage'
+ zh: '前端 (React 19 + Zustand + TailwindCSS 4) → Tauri 2 Commands → Rust 核心层 (rusqlite 0.35) → SQLite (WAL + FTS5) → 本地文件存储'
+ en: 'Frontend (React 19 + Zustand + TailwindCSS 4) → Tauri 2 Commands → Rust Core (rusqlite 0.35) → SQLite (WAL + FTS5) → Local File Storage'
+
+screenshots:
+ - '/screenshots/quantanote/library.png'
+ - '/screenshots/quantanote/note-preview.png'
+ - '/screenshots/quantanote/note-edit.png'
+ - '/screenshots/quantanote/note-version.png'
+ - '/screenshots/quantanote/workspace.png'
+ - '/screenshots/quantanote/search-cmd.png'
+ - '/screenshots/quantanote/settings-appearance.png'
+ - '/screenshots/quantanote/settings-font.png'
+ - '/screenshots/quantanote/settings-data.png'
+ - '/screenshots/quantanote/settings-sync.png'
+ - '/screenshots/quantanote/settings-about.png'
+ - '/screenshots/quantanote/accoun-login.png'
+ - '/screenshots/quantanote/account-register.png'
+ - '/screenshots/quantanote/account-profile.png'
+ - '/screenshots/quantanote/account.png'
+ - '/screenshots/quantanote/topbar-more.png'
+
+installGuide:
+ zh:
+ - platform: 'Windows'
+ icon: '🪟'
+ format: '.exe'
+ tip: 'SmartScreen 拦截?点击"更多信息" → "仍要运行"'
+ - platform: 'macOS'
+ icon: '🍎'
+ format: '.dmg'
+ tip: '提示已损坏?终端运行: xattr -dr com.apple.quarantine /Applications/QuantaNote.app'
+ - platform: 'Linux'
+ icon: '🐧'
+ format: '.AppImage'
+ tip: 'chmod +x QuantaNote-*.AppImage && ./QuantaNote-*.AppImage'
+ en:
+ - platform: 'Windows'
+ icon: '🪟'
+ format: '.exe'
+ tip: 'SmartScreen blocked? Click "More info" → "Run anyway"'
+ - platform: 'macOS'
+ icon: '🍎'
+ format: '.dmg'
+ tip: '"Damaged" error? Run: xattr -dr com.apple.quarantine /Applications/QuantaNote.app'
+ - platform: 'Linux'
+ icon: '🐧'
+ format: '.AppImage'
+ tip: 'chmod +x QuantaNote-*.AppImage && ./QuantaNote-*.AppImage'
diff --git a/src/data/projects/react-docs-ui.yaml b/src/data/projects/react-docs-ui.yaml
index 288ad09..65d9ea0 100644
--- a/src/data/projects/react-docs-ui.yaml
+++ b/src/data/projects/react-docs-ui.yaml
@@ -47,14 +47,13 @@ tags:
- 'NPM'
- 'MDX'
icon: 'BookOpen'
+logo: '/logos/react-docs-ui.png'
repoUrl: 'https://github.com/shenjianZ/react-docs-ui'
docsUrl: 'https://github.com/shenjianZ/react-docs-ui#readme'
npmUrl: 'https://www.npmjs.com/package/react-docs-ui'
latestVersion: 'v0.5.2'
releaseDate: '2026-05-10'
license: 'MIT'
-stars: 203
-forks: 24
language: 'TypeScript'
lastUpdated: '2026-05-18'
recommended: true
diff --git a/src/data/projects/ssh-terminal.yaml b/src/data/projects/ssh-terminal.yaml
index 4f0f4c1..523a61a 100644
--- a/src/data/projects/ssh-terminal.yaml
+++ b/src/data/projects/ssh-terminal.yaml
@@ -50,13 +50,12 @@ tags:
- 'SFTP'
- 'DevOps'
icon: 'Terminal'
+logo: '/logos/ssh-terminal.png'
repoUrl: 'https://github.com/shenjianZ/ssh-terminal'
docsUrl: 'https://github.com/shenjianZ/ssh-terminal#readme'
latestVersion: 'v0.1.5'
releaseDate: '2026-03-28'
license: 'MIT'
-stars: 89
-forks: 8
language: 'Rust'
lastUpdated: '2026-05-08'
recommended: true
diff --git a/src/data/projects/streetmoment.yaml b/src/data/projects/streetmoment.yaml
index b3daddc..3fe904e 100644
--- a/src/data/projects/streetmoment.yaml
+++ b/src/data/projects/streetmoment.yaml
@@ -46,13 +46,12 @@ tags:
- 'Social'
- 'Mobile'
icon: 'MapPin'
+logo: '/logos/streetmoment.png'
repoUrl: 'https://github.com/shenjianZ/streetmoment'
docsUrl: 'https://github.com/shenjianZ/streetmoment#readme'
latestVersion: 'v1.0.0'
releaseDate: '2026-05-01'
license: 'MIT'
-stars: 56
-forks: 5
language: 'TypeScript'
lastUpdated: '2026-05-15'
recommended: false
diff --git a/src/hooks/useProjectFilters.ts b/src/hooks/useProjectFilters.ts
index 8beec68..a015e7c 100644
--- a/src/hooks/useProjectFilters.ts
+++ b/src/hooks/useProjectFilters.ts
@@ -39,8 +39,7 @@ export function useProjectFilters() {
if (platform) result = result.filter((p) => p.platforms.includes(platform));
if (status) result = result.filter((p) => p.status === status);
- if (sort === 'stars') result.sort((a, b) => b.stars - a.stars);
- else if (sort === 'name') result.sort((a, b) => a.name.localeCompare(b.name));
+ if (sort === 'name') result.sort((a, b) => a.name.localeCompare(b.name));
else result.sort((a, b) => b.lastUpdated.localeCompare(a.lastUpdated));
return result;
diff --git a/src/pages/ProjectDetailPage.tsx b/src/pages/ProjectDetailPage.tsx
index 91fca08..b21a414 100644
--- a/src/pages/ProjectDetailPage.tsx
+++ b/src/pages/ProjectDetailPage.tsx
@@ -6,7 +6,7 @@ import RoadmapGrid from '../components/RoadmapGrid';
import ChangelogList from '../components/ChangelogList';
import ScreenshotCarousel from '../components/ScreenshotCarousel';
import { getIcon } from '../utils/iconRegistry';
-import { ExternalLink, Download, BookOpen } from 'lucide-react';
+import { ExternalLink, Download, BookOpen, Globe } from 'lucide-react';
export default function ProjectDetailPage() {
const { id } = useParams();
@@ -44,7 +44,10 @@ export default function ProjectDetailPage() {
- {IconComponent ?
:
{p.icon}}
+ {p.logo
+ ?

+ : (IconComponent ?
:
{p.icon})
+ }
{p.displayName[lang] || p.name}
@@ -70,10 +73,12 @@ export default function ProjectDetailPage() {
-
- {t('common.stars')}
- {p.stars}
-
-
- {t('common.forks')}
- {p.forks}
-
{t('detail.lastUpdate')}
{p.lastUpdated}
@@ -213,6 +196,12 @@ export default function ProjectDetailPage() {
{t('detail.repo')}
+ {p.websiteUrl && (
+
+
+ {t('detail.website')}
+
+ )}
{p.docsUrl && (
diff --git a/src/pages/ProjectsPage.tsx b/src/pages/ProjectsPage.tsx
index 66f6901..f66cacb 100644
--- a/src/pages/ProjectsPage.tsx
+++ b/src/pages/ProjectsPage.tsx
@@ -45,7 +45,6 @@ export default function ProjectsPage() {
];
const sortOptions = [
{ value: 'updated', label: t('projects.sort.updated') },
- { value: 'stars', label: t('projects.sort.stars') },
{ value: 'name', label: t('projects.sort.name') },
];
diff --git a/src/styles/components/cards.css b/src/styles/components/cards.css
index 76c2aba..a1c8fa6 100644
--- a/src/styles/components/cards.css
+++ b/src/styles/components/cards.css
@@ -169,6 +169,13 @@
transform: scale(1.08);
}
+.project-logo {
+ width: 32px;
+ height: 32px;
+ object-fit: contain;
+ border-radius: 4px;
+}
+
.project-card-info {
flex: 1;
min-width: 0;
diff --git a/src/styles/components/detail.css b/src/styles/components/detail.css
index 1dd5bbb..6b02dc1 100644
--- a/src/styles/components/detail.css
+++ b/src/styles/components/detail.css
@@ -70,6 +70,11 @@
background: linear-gradient(135deg, oklch(100% 0 0 / 10%) 0%, transparent 60%);
}
+.detail-icon .project-logo {
+ width: 48px;
+ height: 48px;
+}
+
.detail-title {
font-size: 36px;
font-weight: 800;
@@ -290,12 +295,13 @@
.screenshot-scroll {
display: flex;
+ align-items: flex-start;
gap: 12px;
overflow-x: auto;
+ overflow-y: hidden;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
- padding-bottom: 4px;
}
.screenshot-scroll::-webkit-scrollbar {
@@ -305,13 +311,176 @@
.screenshot-slide {
flex: 0 0 85%;
max-width: 400px;
+ aspect-ratio: 16 / 10;
scroll-snap-align: center;
+ cursor: pointer;
+ overflow: hidden;
}
.screenshot-slide:first-child {
margin-inline-start: 4px;
}
+.screenshot-image {
+ width: 100%;
+ height: 100%;
+ display: block;
+ object-fit: cover;
+ border-radius: var(--radius-md);
+ border: 1px solid var(--border);
+ transition: transform 0.2s, box-shadow 0.2s;
+}
+
+.screenshot-slide:hover .screenshot-image {
+ transform: scale(1.02);
+ box-shadow: 0 4px 20px oklch(0% 0 0 / 30%);
+}
+
+/* Desktop arrows — hidden on mobile */
+.screenshot-arrow {
+ display: none;
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ z-index: 2;
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ border: 1px solid var(--border);
+ background: oklch(15% 0.025 270 / 80%);
+ backdrop-filter: blur(8px);
+ color: var(--fg);
+ cursor: pointer;
+ align-items: center;
+ justify-content: center;
+ transition: all var(--transition);
+}
+
+.screenshot-arrow:hover {
+ background: oklch(74% 0.2 45 / 20%);
+ border-color: oklch(74% 0.2 45 / 30%);
+ color: var(--accent);
+}
+
+.screenshot-arrow-prev {
+ left: 4px;
+}
+
+.screenshot-arrow-next {
+ right: 4px;
+}
+
+@media (min-width: 768px) {
+ .screenshot-slide {
+ flex: 0 0 calc(33.333% - 8px);
+ cursor: pointer;
+ }
+
+ .screenshot-arrow {
+ display: flex;
+ }
+}
+
+/* Lightbox overlay */
+.screenshot-lightbox {
+ position: fixed;
+ inset: 0;
+ z-index: 9999;
+ background: oklch(0% 0 0 / 85%);
+ backdrop-filter: blur(12px);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ cursor: zoom-out;
+ animation: lightbox-in 0.2s ease;
+}
+
+@keyframes lightbox-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+.screenshot-lightbox-img {
+ max-width: 90vw;
+ max-height: 85vh;
+ object-fit: contain;
+ border-radius: var(--radius-lg);
+ box-shadow: 0 8px 40px oklch(0% 0 0 / 50%);
+ cursor: default;
+ animation: lightbox-zoom 0.25s ease;
+}
+
+@keyframes lightbox-zoom {
+ from { transform: scale(0.92); opacity: 0; }
+ to { transform: scale(1); opacity: 1; }
+}
+
+.screenshot-lightbox-close {
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ border: 1px solid oklch(100% 0 0 / 20%);
+ background: oklch(0% 0 0 / 50%);
+ color: oklch(100% 0 0 / 80%);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s;
+ z-index: 10;
+}
+
+.screenshot-lightbox-close:hover {
+ background: oklch(0% 0 0 / 70%);
+ color: oklch(100% 0 0 / 100%);
+}
+
+.screenshot-lightbox-arrow {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ border: 1px solid oklch(100% 0 0 / 20%);
+ background: oklch(0% 0 0 / 40%);
+ color: oklch(100% 0 0 / 80%);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s;
+ z-index: 10;
+}
+
+.screenshot-lightbox-arrow:hover {
+ background: oklch(0% 0 0 / 60%);
+ color: oklch(100% 0 0 / 100%);
+}
+
+.screenshot-lightbox-prev {
+ left: 16px;
+}
+
+.screenshot-lightbox-next {
+ right: 16px;
+}
+
+.screenshot-lightbox-counter {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ color: oklch(100% 0 0 / 60%);
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: 0.05em;
+}
+
.screenshot-placeholder {
aspect-ratio: 16/10;
border-radius: var(--radius-lg);
@@ -365,12 +534,6 @@
box-shadow: 0 0 8px oklch(74% 0.2 45 / 30%);
}
-@media (min-width: 768px) {
- .screenshot-slide {
- flex: 0 0 calc(33.333% - 8px);
- }
-}
-
/* ── Install guide ───────────────────────────────────── */
.install-list {
display: flex;
@@ -405,6 +568,57 @@
letter-spacing: 0.03em;
}
+/* ── Install guide inline (compact) ──────────────────── */
+.install-guide-inline {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ margin-top: 12px;
+ padding: 8px 10px;
+ border-radius: var(--radius-md);
+ border: 1px dashed oklch(74% 0.2 45 / 15%);
+ background: oklch(74% 0.2 45 / 3%);
+}
+
+:root.light .install-guide-inline {
+ border-color: oklch(58% 0.22 45 / 15%);
+ background: oklch(58% 0.22 45 / 3%);
+}
+
+.install-tip-row {
+ display: flex;
+ align-items: baseline;
+ gap: 8px;
+ font-size: 12px;
+ line-height: 1.6;
+ padding: 3px 4px;
+ border-radius: var(--radius-sm);
+}
+
+.install-tip-icon {
+ flex-shrink: 0;
+ font-size: 13px;
+ width: 18px;
+ text-align: center;
+}
+
+.install-tip-format {
+ flex-shrink: 0;
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-weight: 600;
+ color: var(--accent);
+ padding: 1px 6px;
+ border-radius: 4px;
+ background: oklch(74% 0.2 45 / 10%);
+}
+
+.install-tip-text {
+ color: var(--muted);
+ min-width: 0;
+ word-break: break-all;
+}
+
/* ── Project selector (for roadmap/changelog) ────────── */
.project-selector {
display: flex;
diff --git a/src/types/index.ts b/src/types/index.ts
index a712bb4..a77e63c 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -56,6 +56,20 @@ export interface ChangelogEntry {
changes: BilingualArray;
}
+export interface InstallGuideItem {
+ platform: string;
+ icon: string;
+ format: string;
+ tip: string;
+}
+
+export type InstallGuide = InstallGuideItem[];
+
+export interface BilingualInstallGuide {
+ zh: InstallGuide;
+ en: InstallGuide;
+}
+
export interface Project {
id: string;
name: string;
@@ -69,14 +83,14 @@ export interface Project {
features: BilingualArray;
tags: string[];
icon: string;
+ logo?: string;
repoUrl: string;
+ websiteUrl?: string;
docsUrl?: string;
npmUrl?: string;
latestVersion: string;
releaseDate: string;
license: string;
- stars: number;
- forks: number;
language: string;
lastUpdated: string;
recommended: boolean;
@@ -88,6 +102,7 @@ export interface Project {
changelog?: ChangelogEntry[];
architecture?: BilingualText;
screenshots?: string[];
+ installGuide?: BilingualInstallGuide;
}
export interface AboutData {