Add privacy policy modal and enhance project details
CI / build (push) Has been cancelled

- Introduce PolicyModal component for license and privacy policy display
- Add Quick Start section to project detail pages
- Update project descriptions, features, and URLs for several projects
- Add new logos, screenshots, and favicon
- Extend types and configuration for new features
This commit is contained in:
2026-05-26 14:14:37 +08:00
parent fb9aec885f
commit 3ee9b9e6de
31 changed files with 637 additions and 88 deletions
+3 -1
View File
@@ -18,7 +18,9 @@
"Bash(gh api *)",
"Bash(echo \"exit: $?\")",
"Bash(rtk npx *)",
"Bash(rtk tsc *)"
"Bash(rtk tsc *)",
"Bash(netstat -ano)",
"mcp__chrome-devtools__*"
]
}
}
+1
View File
@@ -16,6 +16,7 @@
<meta property="og:description" content="构建轻量、高效、开源的软件工具" />
<meta property="og:type" content="website" />
<meta name="color-scheme" content="dark light" />
<link rel="icon" type="image/webp" href="/logos/app.webp" />
<meta name="twitter:card" content="summary" />
</head>
<body>
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

+10 -4
View File
@@ -1,9 +1,12 @@
import { Link } from 'react-router-dom';
import { useState } from 'react';
import { useI18n } from '../hooks/useI18n';
import { siteData } from '../data/siteData';
import PolicyModal from './PolicyModal';
export default function Footer() {
const { t, bi, lang } = useI18n();
const [policyModal, setPolicyModal] = useState<'license' | 'privacy' | null>(null);
return (
<footer className="footer">
@@ -43,13 +46,13 @@ export default function Footer() {
<div className="footer-bottom">
<span>{t('footer.copyright')}</span>
<span className="footer-policy-links">
<Link to="/about" className="footer-policy-link">
<button type="button" className="footer-policy-link" onClick={() => setPolicyModal('license')}>
{t('footer.license')}
</Link>
</button>
{' · '}
<Link to="/about" className="footer-policy-link">
<button type="button" className="footer-policy-link" onClick={() => setPolicyModal('privacy')}>
{t('footer.privacy')}
</Link>
</button>
</span>
<span className="footer-legal">
{siteData.brand.icp && (
@@ -65,6 +68,9 @@ export default function Footer() {
</span>
</div>
</div>
{policyModal && (
<PolicyModal type={policyModal} onClose={() => setPolicyModal(null)} />
)}
</footer>
);
}
+204
View File
@@ -0,0 +1,204 @@
import { useEffect } from 'react';
import { createPortal } from 'react-dom';
import { X, Scale, ShieldCheck } from 'lucide-react';
import { useI18n } from '../hooks/useI18n';
interface PolicyModalProps {
type: 'license' | 'privacy';
onClose: () => void;
}
export default function PolicyModal({ type, onClose }: PolicyModalProps) {
const { t, lang } = useI18n();
const title = type === 'license' ? t('footer.license') : t('footer.privacy');
useEffect(() => {
const prev = document.body.style.overflow;
document.body.style.overflow = 'hidden';
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
return () => {
document.body.style.overflow = prev;
window.removeEventListener('keydown', onKey);
};
}, [onClose]);
return createPortal(
<div className="policy-overlay" onClick={onClose}>
<div className="policy-modal" onClick={(e) => e.stopPropagation()}>
<div className="policy-modal-header">
<div className="policy-modal-header-left">
{type === 'license' ? <Scale size={20} /> : <ShieldCheck size={20} />}
<h3 className="policy-modal-title">{title}</h3>
</div>
<button className="policy-modal-close" onClick={onClose} aria-label="Close">
<X size={20} />
</button>
</div>
<div className="policy-modal-body">
{type === 'license' ? <LicenseContent /> : <PrivacyContent lang={lang} />}
</div>
</div>
</div>,
document.body
);
}
function LicenseContent() {
const { lang } = useI18n();
return (
<div className="policy-content">
<div className="policy-badge">MIT License</div>
<section className="policy-section">
<h4>Copyright &copy; 2026 ZUJ OL</h4>
<p className="policy-highlight">
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the &ldquo;Software&rdquo;),
to deal in the Software without restriction, including without limitation the
rights to <strong>use</strong>, <strong>copy</strong>, <strong>modify</strong>,{' '}
<strong>merge</strong>, <strong>publish</strong>, <strong>distribute</strong>,{' '}
<strong>sublicense</strong>, and/or <strong>sell</strong> copies of the Software.
</p>
</section>
<section className="policy-section">
<h4>Conditions</h4>
<p>
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
</p>
</section>
<section className="policy-section">
<h4>Disclaimer</h4>
<p className="policy-muted">
THE SOFTWARE IS PROVIDED &ldquo;AS IS&rdquo;, 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.
</p>
</section>
<footer className="policy-footer">
{lang === 'zh' ? '完整协议文本请访问 ' : 'Full text available at '}
<a href="https://opensource.org/licenses/MIT" target="_blank" rel="noopener noreferrer">
opensource.org/licenses/MIT
</a>
</footer>
</div>
);
}
function PrivacyContent({ lang }: { lang: string }) {
if (lang === 'zh') {
return (
<div className="policy-content">
<p className="policy-intro">
ZUJ OL Apps
</p>
<section className="policy-section">
<h4><span className="policy-num">1</span> </h4>
<p>
使 CookiePII使
Vercel Analytics 访
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">2</span> </h4>
<p>
GitHubnpm
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">3</span> </h4>
<p>
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">4</span> </h4>
<p>
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">5</span> </h4>
<p>
{' '}
<a href="https://github.com/shenjianZ" target="_blank" rel="noopener noreferrer">GitHub Issues</a>
{' '}
</p>
</section>
<footer className="policy-footer">
2026 5
</footer>
</div>
);
}
return (
<div className="policy-content">
<p className="policy-intro">
This privacy policy applies to the ZUJ OL Apps website. We respect your privacy
and are committed to protecting your personal information.
</p>
<section className="policy-section">
<h4><span className="policy-num">1</span> Information Collection</h4>
<p>
This project does not use cookies and does not collect any personally identifiable
information (PII). We may use privacy-first analytics tools such as Vercel Analytics
to collect anonymous access data (e.g., page views, browser type) to help improve
the website experience.
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">2</span> Third-Party Links</h4>
<p>
This website contains links to external third-party websites such as GitHub and npm.
We are not responsible for the privacy policies of these websites.
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">3</span> Data Security</h4>
<p>
We take reasonable security measures to protect the operation of the website, but
cannot guarantee absolute security of internet transmissions.
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">4</span> Policy Updates</h4>
<p>
We may update this privacy policy from time to time. Any changes will be posted
on this page.
</p>
</section>
<section className="policy-section">
<h4><span className="policy-num">5</span> Contact</h4>
<p>
If you have any questions about this privacy policy, please contact us via{' '}
<a href="https://github.com/shenjianZ" target="_blank" rel="noopener noreferrer">GitHub Issues</a>.
</p>
</section>
<footer className="policy-footer">
Last updated: May 2026
</footer>
</div>
);
}
+6
View File
@@ -1,5 +1,6 @@
import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react';
import type { AppContextType } from '../types';
import { siteData } from '../data/loader';
const AppContext = createContext<AppContextType | null>(null);
@@ -17,6 +18,11 @@ export function AppProvider({ children }: { children: ReactNode }) {
localStorage.setItem('theme', theme);
}, [theme]);
useEffect(() => {
const { name, slogan } = siteData.brand;
document.title = `${name[lang]}${slogan[lang]}`;
}, [lang]);
const toggleTheme = useCallback(() => {
setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'));
}, []);
+1 -1
View File
@@ -4,7 +4,7 @@ name:
slogan:
zh: '构建轻量、高效、开源的软件工具'
en: 'Building lightweight, efficient, open-source software tools'
logo: '/logo.svg'
logo: '/logos/app.webp'
author: 'shenjianZ'
github: 'https://github.com/shenjianZ'
email: '15202078626@163.com'
+1
View File
@@ -33,6 +33,7 @@ projects.sort.name: 'By Name'
projects.noResults: 'No matching projects'
projects.search: 'Search project name, description, or tags...'
detail.overview: 'Overview'
detail.quickStart: 'Quick Start'
detail.features: 'Features'
detail.screenshots: 'Screenshots'
detail.downloads: 'Downloads'
+1
View File
@@ -33,6 +33,7 @@ projects.sort.name: '名称排序'
projects.noResults: '没有匹配的项目'
projects.search: '搜索项目名称、描述或标签...'
detail.overview: '概览'
detail.quickStart: '快速开始'
detail.features: '核心功能'
detail.screenshots: '截图预览'
detail.downloads: '下载安装'
+58 -11
View File
@@ -45,6 +45,11 @@ features:
- '操作日志查看与管理'
- '环境检测(ADB / scrcpy'
- '字号自定义(12-16px'
- 'WiFi 文件传输实时事件推送(WebSocket'
- '分片上传与断点续传(SHA-256 校验)'
- '传输历史记录追踪'
- '批量下载'
- '文件预览(扩展 MIME 识别)'
en:
- 'Android device scanning & management (USB / WiFi)'
- 'Scrcpy mirroring with multiple preset configs'
@@ -62,6 +67,11 @@ features:
- 'Operation log viewer & management'
- 'Environment check (ADB / scrcpy)'
- 'Font size customization (12-16px)'
- 'WiFi file transfer real-time event push (WebSocket)'
- 'Chunked upload with resume (SHA-256 verification)'
- 'Transfer history tracking'
- 'Batch download'
- 'File preview (extended MIME recognition)'
tags:
- 'Android'
- 'ADB'
@@ -76,11 +86,11 @@ logo: '/logos/devicedeck.png'
repoUrl: 'https://github.com/shenjianZ/devicedeck'
websiteUrl: 'https://shenjianz.github.io/DeviceDeck/'
docsUrl: 'https://github.com/shenjianZ/devicedeck#readme'
latestVersion: 'v0.1.1'
releaseDate: '2026-05-18'
latestVersion: 'v0.1.3'
releaseDate: '2026-05-23'
license: 'MIT'
language: 'Rust'
lastUpdated: '2026-05-18'
lastUpdated: '2026-05-23'
recommended: true
featured: true
order: 4
@@ -88,23 +98,23 @@ color: '#8B5CF6'
downloads:
- platform: 'Windows'
arch: 'x64'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.1/DeviceDeck-v0.1.1-windows-x64.exe'
size: '17.5 MB'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.3/DeviceDeck-v0.1.3-windows-x64.exe'
size: '18.31 MB'
sha256: ''
- platform: 'macOS'
arch: 'Apple Silicon'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.1/DeviceDeck-v0.1.1-macos-aarch64.dmg'
size: '35.8 MB'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.3/DeviceDeck-v0.1.3-macos-aarch64.dmg'
size: '34.62 MB'
sha256: ''
- platform: 'macOS'
arch: 'Intel'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.1/DeviceDeck-v0.1.1-macos-x64.dmg'
size: '36.0 MB'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.3/DeviceDeck-v0.1.3-macos-x64.dmg'
size: '34.9 MB'
sha256: ''
- platform: 'Linux'
arch: 'x64'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.1/DeviceDeck-v0.1.1-linux-x64.AppImage'
size: '98.8 MB'
url: 'https://file.shenjianl.cn/softwore/DeviceDeck/v0.1.3/DeviceDeck-v0.1.3-linux-x64.AppImage'
size: '99.9 MB'
sha256: ''
roadmap:
done:
@@ -123,6 +133,11 @@ roadmap:
- 'WiFi 文件传输'
- '环境检测'
- '首次启动欢迎引导'
- 'WiFi 文件传输实时事件推送'
- '分片上传与断点续传'
- '传输历史记录'
- '批量下载'
- '文件预览'
doing:
- '多设备同时投屏'
- '脚本录制回放'
@@ -130,6 +145,38 @@ roadmap:
- 'iOS 设备支持'
- '自动化测试集成'
changelog:
- version: 'v0.1.3'
date: '2026-05-23'
changes:
zh:
- '新增 WebSocket 实时文件事件通知'
- '新增文件预览支持,扩展 MIME 类型识别'
- '新增分片上传与断点续传(SHA-256 校验)'
- '新增传输历史记录追踪'
- '新增批量下载端点'
- '新增文件筛选/排序下拉框自定义组件'
- 'WiFi 传输模块大幅增强,引入 tokio broadcast channel 驱动事件广播'
en:
- 'Added WebSocket real-time file event notifications'
- 'Added file preview with extended MIME type recognition'
- 'Added chunked upload with resume (SHA-256 verification)'
- 'Added transfer history tracking'
- 'Added batch download endpoint'
- 'Added custom file filter/sort dropdown component'
- 'Major WiFi transfer module enhancement with tokio broadcast channel'
- version: 'v0.1.2'
date: '2026-05-22'
changes:
zh:
- '新增项目官方网站(React 19 + Vite'
- '新增 WiFi 文件传输独立 Web 页面'
- '新增 GitHub Actions 自动部署工作流'
- '优化所有平台图标文件体积'
en:
- 'Added official project website (React 19 + Vite)'
- 'Added standalone WiFi file transfer web page'
- 'Added GitHub Actions auto-deploy workflow'
- 'Optimized all platform icon file sizes'
- version: 'v0.1.1'
date: '2026-05-18'
changes:
+63 -69
View File
@@ -4,11 +4,11 @@ displayName:
zh: 'React Docs UI'
en: 'React Docs UI'
slogan:
zh: '基于 React 文档组件库与站点生成器'
en: 'React-based documentation component library & site generator'
zh: '配置驱动的 React 文档站点组件库与脚手架'
en: 'Configuration-driven React documentation site components & scaffolding'
description:
zh: 'react-docs-ui 是一套用于构建文档站点的 React 组件库,配合 create-react-docs-ui 脚手架可快速搭建类似 Nextra / Docusaurus 风格的文档网站。支持 MDX、全文搜索、版本切换和主题定制。'
en: 'react-docs-ui is a React component library for building documentation sites. Paired with create-react-docs-ui scaffolding, it quickly sets up Nextra/Docusaurus-style docs sites. Supports MDX, full-text search, version switching, and theme customization.'
zh: 'react-docs-ui 是一套 React 文档站点 UI 组件库,配合 create-react-docs-ui 脚手架可快速搭建 Nextra / Docusaurus 风格的文档网站。基于 site.yaml 配置驱动,支持 MD/MDX、Shiki 代码高亮、全文搜索、版本切换、深浅主题、命令菜单、国际化、Mermaid 图表、KaTeX 数学公式、面包屑导航、RSS Feed、Sitemap 生成、PWA 支持、后端集成(认证、评论、书签、分析统计)、PDF/DOCX 导出等功能,并内置 CLI 工具链(搜索索引、llms.txt、changelog 索引生成)。'
en: 'react-docs-ui is a React component library for building documentation sites. Paired with create-react-docs-ui scaffolding, it quickly sets up Nextra/Docusaurus-style docs. Configuration-driven via site.yaml, supporting MD/MDX, Shiki syntax highlighting, full-text search, version switching, light/dark themes, command menu, i18n, Mermaid diagrams, KaTeX math, breadcrumbs, RSS Feed, Sitemap generation, PWA, backend integration (auth, comments, bookmarks, analytics), PDF/DOCX export, and built-in CLI toolchain (search index, llms.txt, changelog index generation).'
type:
- 'library'
- 'devtool'
@@ -17,89 +17,83 @@ platforms:
- 'web'
- 'npm'
techStack:
- 'React'
- 'React 19'
- 'TypeScript'
- 'MDX'
- 'TailwindCSS'
- 'Vite'
- 'TailwindCSS 4'
- 'shadcn/ui'
- 'Radix UI'
- 'MDX'
- 'Shiki'
- 'react-markdown'
- 'Mermaid'
- 'KaTeX'
- 'FlexSearch'
- 'next-themes'
- 'cmdk'
- 'lucide-react'
- 'jsPDF'
- 'Docx'
features:
zh:
- 'MDX 支持'
- '全文搜索'
- '版本切换'
- '主题定制'
- '响应式布局'
- 'API 文档生成'
- '代码高亮'
- '国际化'
- '配置驱动(site.yaml),配套 create-react-docs-ui 一键脚手架快速搭建文档站点'
- 'MD/MDX 渲染(GFM 扩展语法、Tabs、自定义图片组件)+ Shiki 代码高亮(100+ 主题)'
- '全文搜索(FlexSearch 索引 + Cmd+K 命令菜单)'
- '文档多版本控制与切换'
- 'Mermaid 图表 + KaTeX 数学公式渲染'
- 'SEO 与内容发现(元标签自动注入、RSS Feed、Sitemap、llms.txt 生成'
- '深色/浅色/跟随系统主题、国际化(多语言路由)、PWA 支持'
- '导航体验:面包屑、目录导航(TOC)、上下文菜单、阅读进度条'
- 'Changelog / Release Notes 页面模块与用户反馈'
- '后端集成:用户认证(邮箱 + OAuth)、评论系统(线程回复)、书签、分析统计'
- 'PDF / DOCX 文档导出'
- '内置 CLI 工具链(搜索索引、changelog 索引、sitemap、feed 生成)'
en:
- 'MDX support'
- 'Full-text search'
- 'Version switching'
- 'Theme customization'
- 'Responsive layout'
- 'API doc generation'
- 'Code highlighting'
- 'i18n'
- 'Configuration-driven (site.yaml) with create-react-docs-ui one-command scaffolding'
- 'MD/MDX rendering (GFM, Tabs, custom image components) + Shiki syntax highlighting (100+ themes)'
- 'Full-text search (FlexSearch index + Cmd+K command menu)'
- 'Multi-version documentation control & switching'
- 'Mermaid diagrams + KaTeX math formula rendering'
- 'SEO & content discovery (meta tag injection, RSS Feed, Sitemap, llms.txt generation)'
- 'Dark/Light/Follow system theme, internationalization (multi-language routing), PWA support'
- 'Navigation: breadcrumbs, Table of Contents (TOC), context menu, reading progress bar'
- 'Changelog / Release Notes page module with user feedback'
- 'Backend integration: auth (email + OAuth), threaded comments, bookmarks, analytics'
- 'PDF / DOCX document export'
- 'Built-in CLI toolchain (search index, changelog index, sitemap, feed generation)'
tags:
- 'Documentation'
- 'React'
- 'NPM'
- 'MDX'
- 'CLI'
- 'Component Library'
- 'Static Site'
- 'TypeScript'
- 'Vite'
- 'TailwindCSS'
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'
websiteUrl: 'https://shenjianz.github.io/react-docs-ui'
docsUrl: 'https://react-docs-ui.shenjianl.cn/'
npmUrl: 'https://www.npmjs.com/package/react-docs-ui'
latestVersion: 'v0.5.2'
releaseDate: '2026-05-10'
latestVersion: 'v0.9.2'
releaseDate: '2025-08-10'
license: 'MIT'
language: 'TypeScript'
lastUpdated: '2026-05-18'
lastUpdated: '2026-05-05'
recommended: true
featured: true
order: 5
color: '#06B6D4'
downloads: []
roadmap:
done:
- '基础组件库'
- 'MDX 渲染'
- '侧边栏导航'
- '搜索功能'
- '主题系统'
doing:
- 'API 文档自动生成'
- '版本切换'
- '性能优化'
planned:
- '插件系统'
- '评论集成'
- '多语言路由'
- 'CLI 工具'
changelog:
- version: 'v0.5.2'
date: '2026-05-10'
changes:
zh:
- '修复搜索索引构建错误'
- '新增代码块复制按钮'
- '优化移动端导航'
en:
- 'Fixed search index build error'
- 'Added code copy button'
- 'Improved mobile navigation'
- version: 'v0.5.0'
date: '2026-04-01'
changes:
zh:
- '新增主题定制'
- '支持 MDX 嵌入组件'
- '新增面包屑导航'
en:
- 'Added theme customization'
- 'MDX embedded components'
- 'Breadcrumb navigation'
architecture:
zh: 'MDX 源文件 → Vite 构建 → React 组件渲染 → 静态文档站点'
en: 'MDX Sources → Vite Build → React Component Rendering → Static Documentation Site'
quickStart:
zh:
- 'pnpm create react-docs-ui@latest my-docs'
- 'cd my-docs && pnpm install'
- 'pnpm dev'
en:
- 'pnpm create react-docs-ui@latest my-docs'
- 'cd my-docs && pnpm install'
- 'pnpm dev'
+16 -2
View File
@@ -84,7 +84,8 @@ tags:
icon: 'Terminal'
logo: '/logos/ssh-terminal.png'
repoUrl: 'https://github.com/shenjianZ/ssh-terminal'
docsUrl: 'https://github.com/shenjianZ/ssh-terminal#readme'
websiteUrl: 'https://shenjianz.github.io/ssh-terminal'
docsUrl: 'http://st-docs.shenjianl.cn'
latestVersion: 'v1.2.1'
releaseDate: '2026-03-04'
license: 'MIT'
@@ -167,7 +168,20 @@ architecture:
zh: '前端 (React 19 + xterm.js + Zustand + shadcn/ui) → Tauri 2 Commands → Rust 服务层 (russh + r2d2_sqlite + aes-gcm) → SQLite / 远程服务器'
en: 'Frontend (React 19 + xterm.js + Zustand + shadcn/ui) → Tauri 2 Commands → Rust Service Layer (russh + r2d2_sqlite + aes-gcm) → SQLite / Remote Server'
screenshots: []
screenshots:
- '/screenshots/ssh-terminal/terminal-main.png'
- '/screenshots/ssh-terminal/session-manager.png'
- '/screenshots/ssh-terminal/aichat-page.png'
- '/screenshots/ssh-terminal/terminal-ai-short-page.png'
- '/screenshots/ssh-terminal/terminal-nl-to-cmd.png'
- '/screenshots/ssh-terminal/sftp-manager.png'
- '/screenshots/ssh-terminal/recording-manager.png'
- '/screenshots/ssh-terminal/setting-main.png'
- '/screenshots/ssh-terminal/setting-terminal.png'
- '/screenshots/ssh-terminal/setting-ai.png'
- '/screenshots/ssh-terminal/setting-keybingdings.png'
- '/screenshots/ssh-terminal/setting-reacording.png'
- '/screenshots/ssh-terminal/setting-about.png'
installGuide:
zh:
+15
View File
@@ -110,6 +110,21 @@ export default function ProjectDetailPage() {
<p className="detail-prose">{bi(p.description)}</p>
</div>
{/* Quick Start */}
{p.quickStart && p.quickStart[lang] && p.quickStart[lang].length > 0 && (
<div className="detail-section">
<h2 className="detail-section-title">{t('detail.quickStart')}</h2>
<div className="quickstart-commands">
{p.quickStart[lang].map((cmd, i) => (
<div key={i} className="quickstart-line">
<span className="quickstart-prompt">$</span>
<code className="quickstart-cmd">{cmd}</code>
</div>
))}
</div>
</div>
)}
{/* Features */}
<div className="detail-section">
<h2 className="detail-section-title">{t('detail.features')}</h2>
+52
View File
@@ -114,6 +114,10 @@
padding-bottom: 40px;
}
.detail-body > * {
min-width: 0;
}
.detail-sidebar {
position: sticky;
top: calc(var(--nav-height) + 32px);
@@ -288,6 +292,12 @@
background: oklch(58% 0.22 45 / 14%);
}
@media (max-width: 767px) {
.feature-tag {
white-space: normal;
}
}
/* Screenshot carousel */
.screenshot-carousel {
position: relative;
@@ -619,6 +629,48 @@
word-break: break-all;
}
/* ── Quick start commands ─────────────────────────────── */
.quickstart-commands {
background: oklch(12% 0.02 270);
border: 1px solid oklch(74% 0.2 45 / 12%);
border-radius: var(--radius-lg);
padding: 18px 20px;
display: flex;
flex-direction: column;
gap: 6px;
overflow-x: auto;
}
:root.light .quickstart-commands {
background: oklch(97% 0.005 270);
border-color: oklch(58% 0.22 45 / 12%);
}
.quickstart-line {
display: flex;
align-items: baseline;
gap: 10px;
font-size: 13px;
line-height: 1.7;
}
.quickstart-prompt {
color: var(--accent);
font-weight: 700;
flex-shrink: 0;
user-select: none;
}
.quickstart-cmd {
font-family: var(--font-mono);
color: oklch(90% 0.01 270);
word-break: break-all;
}
:root.light .quickstart-cmd {
color: oklch(25% 0.02 270);
}
/* ── Project selector (for roadmap/changelog) ────────── */
.project-selector {
display: flex;
+204
View File
@@ -105,4 +105,208 @@
.footer-policy-link {
color: var(--muted);
cursor: pointer;
background: none;
border: none;
font: inherit;
padding: 0;
}
.footer-policy-link:hover {
color: var(--accent);
}
/* ── Policy Modal ────────────────────────────────────── */
.policy-overlay {
position: fixed;
inset: 0;
z-index: 9999;
background: oklch(0% 0 0 / 70%);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
animation: policy-fade-in 0.2s ease;
}
@keyframes policy-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.policy-modal {
width: 100%;
max-width: 600px;
max-height: 80vh;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 16px 48px oklch(0% 0 0 / 40%);
animation: policy-zoom-in 0.25s ease;
}
@keyframes policy-zoom-in {
from { transform: scale(0.95); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.policy-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.policy-modal-header-left {
display: flex;
align-items: center;
gap: 10px;
color: var(--accent);
}
.policy-modal-title {
font-size: 18px;
font-weight: 700;
letter-spacing: -0.01em;
}
.policy-modal-close {
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid var(--border);
background: transparent;
color: var(--muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition);
}
.policy-modal-close:hover {
color: var(--fg);
background: oklch(74% 0.2 45 / 8%);
border-color: oklch(74% 0.2 45 / 20%);
}
.policy-modal-body {
padding: 24px;
overflow-y: auto;
font-size: 14px;
line-height: 1.8;
color: var(--fg);
}
.policy-modal-body p {
margin-bottom: 16px;
}
.policy-modal-body p:last-child {
margin-bottom: 0;
}
/* Structured content layout */
.policy-content {
display: flex;
flex-direction: column;
gap: 20px;
}
.policy-badge {
display: inline-flex;
align-self: flex-start;
padding: 4px 14px;
border-radius: 99px;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.03em;
background: oklch(74% 0.2 45 / 10%);
color: var(--accent);
border: 1px solid oklch(74% 0.2 45 / 15%);
}
.policy-intro {
font-size: 14px;
line-height: 1.7;
color: var(--muted);
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.policy-section h4 {
font-size: 15px;
font-weight: 700;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.policy-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 50%;
background: oklch(74% 0.2 45 / 10%);
color: var(--accent);
font-size: 12px;
font-weight: 700;
flex-shrink: 0;
}
.policy-section p {
font-size: 14px;
line-height: 1.75;
color: var(--fg);
}
.policy-section a {
color: var(--accent);
text-decoration: underline;
text-underline-offset: 2px;
}
.policy-section a:hover {
text-decoration-thickness: 2px;
}
.policy-highlight {
padding: 14px 16px;
border-radius: var(--radius-md);
background: oklch(74% 0.2 45 / 5%);
border-left: 3px solid var(--accent);
font-size: 13.5px;
line-height: 1.75;
}
.policy-highlight strong {
color: var(--accent);
font-weight: 600;
}
.policy-muted {
font-size: 12.5px;
line-height: 1.7;
color: var(--muted);
}
.policy-footer {
font-size: 12px;
color: var(--muted);
padding-top: 12px;
border-top: 1px solid var(--border);
}
.policy-footer a {
color: var(--accent);
}
+1
View File
@@ -102,6 +102,7 @@ export interface Project {
changelog?: ChangelogEntry[];
architecture?: BilingualText;
screenshots?: string[];
quickStart?: BilingualArray;
installGuide?: BilingualInstallGuide;
}
+1
View File
@@ -20,6 +20,7 @@ export default defineConfig({
assetsInlineLimit: 4096,
},
server: {
host: true,
warmup: {
clientFiles: ['./src/data/loader.ts'],
},