forked from boos/BoosAPI
feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useData } from 'vitepress';
|
||||
import {
|
||||
AppleOutlined,
|
||||
WindowsOutlined,
|
||||
ReadOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
declare const __APP_VERSION__: string;
|
||||
const VERSION = __APP_VERSION__;
|
||||
|
||||
const { lang } = useData();
|
||||
const isZh = computed(() => lang.value === 'zh-CN');
|
||||
|
||||
const detectedOS = ref<'macos' | 'windows' | 'linux'>('macos');
|
||||
|
||||
onMounted(() => {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('win')) {
|
||||
detectedOS.value = 'windows';
|
||||
} else if (ua.includes('linux')) {
|
||||
detectedOS.value = 'linux';
|
||||
} else {
|
||||
detectedOS.value = 'macos';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="download-bar">
|
||||
<a href="/download" class="dl-btn dl-primary">
|
||||
<AppleOutlined v-if="detectedOS === 'macos'" class="os-icon" />
|
||||
<WindowsOutlined v-else-if="detectedOS === 'windows'" class="os-icon" />
|
||||
<svg v-else class="os-icon" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 448 512" fill="currentColor"><path d="M220.8 123.3c1 .5 1.8 1.7 3 1.7 1.1 0 2.8-.4 2.9-1.5.2-1.4-1.9-2.3-3.2-2.9-1.7-.7-3.9-1-5.5-.1-.4.2-.8.7-.6 1.1.3 1.3 2.3 1.1 3.4 1.7zm-21.9 1.7c1.2 0 2-1.2 3-1.7 1.1-.6 3.1-.4 3.5-1.6.2-.4-.2-.9-.6-1.1-1.6-.9-3.8-.6-5.5.1-1.3.6-3.4 1.5-3.2 2.9.1 1 1.8 1.5 2.8 1.4zM420 403.8c-3.6-4-5.3-11.6-7.2-19.7-1.8-8.1-3.9-16.8-10.5-22.4-1.3-1.1-2.6-2.1-4-2.9-1.3-.8-2.7-1.5-4.1-2 9.2-27.3 5.6-54.5-3.7-79.1-11.4-30.1-31.3-56.4-46.5-74.4-17.1-21.5-33.7-41.9-33.4-72C311.1 85.4 315.7.1 234.8 0 132.4-.2 158 85.4 157.7 130.9c.3 30.4-16.3 51-33.4 72-15.2 18-35.1 44.3-46.5 74.4-9.3 24.6-12.9 51.8-3.7 79.1-1.4.5-2.8 1.2-4.1 2-1.4.8-2.7 1.8-4 2.9-6.6 5.6-8.7 14.3-10.5 22.4-1.9 8.1-3.6 15.7-7.2 19.7-6.3 6.7-7.1 16.5-3.5 22.9 3.6 6.4 11.5 9.5 18.5 6.9 3.6-1.3 6.5-4 9.1-6.5 2.5-2.5 4.9-5 7.9-6.5 5.4-2.8 12.4-2.3 19-1.2 6.8 1.2 13.2 3.1 18.8 1.9 12.2-2.6 16.5-11.1 23.7-16.9.5-.4.4-1.2-.1-1.6-.4-.3-1-.3-1.4.1-3.6 4-10.1 12.6-19.4 14.5-5.1 1-11.1-1-17.5-2.1-6.4-1.2-13.5-1.6-19.4 1.4-3.5 1.8-6.1 4.6-8.7 7.1-2.6 2.6-5.1 4.9-8.2 6-4.3 1.6-9.4-.3-11.7-4.4-2.3-4.1-1.7-10.6 2.6-15.1 4.5-4.9 6.3-13.5 8.2-21.5 1.9-8.1 3.9-16.3 9.6-21.1 2.4-2 5.3-3.2 8.3-3.5 2 12.3 9.2 23.4 19.5 31.1 1.4 1 1 3.6-.5 4.1-5.1 1.6-7.4 6.5-4.8 10.4 2.5 3.7 7.9 4.7 11.6 2.2 3.8-2.5 5.1-7.8 2.6-11.6-.5-.8-1.2-1.4-1.9-1.9 1.4-.5 2.4-1.8 2.1-3.2-.3-1.3-1.7-2.2-3-2.2h-.7c3.4-3.7 6.2-8.1 7.9-13 4.3.3 8.4 2 11.3 5.1 4.4 4.8 5.3 11.7 7.1 18 1.8 6.2 4.5 12.4 10.2 15.7 2.5 1.4 5.6 2 8.5 1 2.5-.9 4.3-3.1 5-5.7.4-1.5.2-3.1-.4-4.5-1.4-3.2-4.6-5-7.6-6.6-3-1.5-6.2-3-8-5.8-1.6-2.5-2-5.6-1.2-8.5.6-2.2 2.1-4.2 4.2-5 3.2-1.2 6.7.3 8.5 3.1 1 1.5 1.4 3.4 1.2 5.2.2.5.4 1 .5 1.5.3 1 .5 2.1.5 3.2 0 3.5-1.3 6.8-3.5 9.3 2.4 1.7 5.2 2.7 8.2 2.7 4.4 0 8.5-2.1 11.1-5.5 2.8-3.7 3.5-8.6 1.8-12.9z"/></svg>
|
||||
<span>{{ isZh ? '下载' : 'Download' }} v{{ VERSION }}</span>
|
||||
</a>
|
||||
<a href="/features" class="dl-btn dl-docs">
|
||||
<ReadOutlined class="os-icon" />
|
||||
<span>{{ isZh ? '文档' : 'Docs' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.download-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
padding: 32px 0 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.dl-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
padding: 0 36px;
|
||||
height: 56px;
|
||||
border-radius: 28px;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dl-primary {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.dl-primary:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.dark .dl-primary {
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dl-docs {
|
||||
color: var(--vp-c-text-1);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: transparent;
|
||||
}
|
||||
.dl-docs:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.os-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.dl-btn {
|
||||
padding: 0 28px;
|
||||
height: 50px;
|
||||
font-size: 15px;
|
||||
border-radius: 25px;
|
||||
gap: 8px;
|
||||
}
|
||||
.download-bar {
|
||||
gap: 14px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.dl-btn {
|
||||
padding: 0 24px;
|
||||
height: 48px;
|
||||
font-size: 15px;
|
||||
border-radius: 24px;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
.download-bar {
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 24px 16px 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,452 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useData } from 'vitepress';
|
||||
import {
|
||||
AppleOutlined,
|
||||
WindowsOutlined,
|
||||
ClockCircleOutlined,
|
||||
LinkOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
declare const __APP_VERSION__: string;
|
||||
|
||||
const VERSION = __APP_VERSION__;
|
||||
const BASE = `https://github.com/AQBot-Desktop/AQBot/releases/download/v${VERSION}`;
|
||||
|
||||
type OS = 'macos' | 'windows' | 'linux';
|
||||
|
||||
interface DownloadItem {
|
||||
labelZh: string;
|
||||
labelEn: string;
|
||||
file: string;
|
||||
arch: string;
|
||||
os: OS;
|
||||
primary?: boolean;
|
||||
}
|
||||
|
||||
const downloads: DownloadItem[] = [
|
||||
{ os: 'macos', arch: 'Apple Silicon', labelEn: 'Apple Silicon (M1/M2/M3/M4)', labelZh: 'Apple Silicon(M 系列芯片)', file: `AQBot_${VERSION}_aarch64.dmg`, primary: true },
|
||||
{ os: 'macos', arch: 'Intel', labelEn: 'Intel', labelZh: 'Intel(英特尔芯片)', file: `AQBot_${VERSION}_x64.dmg`, primary: true },
|
||||
{ os: 'windows', arch: 'x64', labelEn: 'Windows x64', labelZh: 'Windows x64', file: `AQBot_${VERSION}_x64-setup.exe`, primary: true },
|
||||
{ os: 'windows', arch: 'x64 Portable', labelEn: 'Windows x64 Portable', labelZh: 'Windows x64 绿色版', file: `AQBot_v${VERSION}_windows-x64-portable.zip` },
|
||||
{ os: 'windows', arch: 'ARM64', labelEn: 'Windows ARM64', labelZh: 'Windows ARM64', file: `AQBot_${VERSION}_arm64-setup.exe` },
|
||||
{ os: 'windows', arch: 'ARM64 Portable', labelEn: 'Windows ARM64 Portable', labelZh: 'Windows ARM64 绿色版', file: `AQBot_v${VERSION}_windows-arm64-portable.zip` },
|
||||
{ os: 'linux', arch: 'x64 deb', labelEn: 'x64 .deb (Debian/Ubuntu)', labelZh: 'x64 .deb(Debian/Ubuntu)', file: `AQBot_${VERSION}_amd64.deb`, primary: true },
|
||||
{ os: 'linux', arch: 'x64 AppImage', labelEn: 'x64 AppImage', labelZh: 'x64 AppImage', file: `AQBot_${VERSION}_amd64.AppImage` },
|
||||
{ os: 'linux', arch: 'ARM64 deb', labelEn: 'ARM64 .deb', labelZh: 'ARM64 .deb', file: `AQBot_${VERSION}_arm64.deb` },
|
||||
{ os: 'linux', arch: 'x64 rpm', labelEn: 'x64 .rpm (Fedora/RHEL)', labelZh: 'x64 .rpm(Fedora/RHEL)', file: `AQBot-${VERSION}-1.x86_64.rpm` },
|
||||
{ os: 'linux', arch: 'ARM64 rpm', labelEn: 'ARM64 .rpm', labelZh: 'ARM64 .rpm', file: `AQBot-${VERSION}-1.aarch64.rpm` },
|
||||
];
|
||||
|
||||
const osTabs: { id: OS; label: string }[] = [
|
||||
{ id: 'macos', label: 'macOS' },
|
||||
{ id: 'windows', label: 'Windows' },
|
||||
{ id: 'linux', label: 'Linux' },
|
||||
];
|
||||
|
||||
const { lang } = useData();
|
||||
const isZh = computed(() => lang.value === 'zh-CN');
|
||||
|
||||
const activeOS = ref<OS>('macos');
|
||||
|
||||
onMounted(() => {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('win')) {
|
||||
activeOS.value = 'windows';
|
||||
} else if (ua.includes('linux')) {
|
||||
activeOS.value = 'linux';
|
||||
} else {
|
||||
activeOS.value = 'macos';
|
||||
}
|
||||
});
|
||||
|
||||
const currentDownloads = computed(() =>
|
||||
downloads.filter(d => d.os === activeOS.value)
|
||||
);
|
||||
|
||||
function itemLabel(item: DownloadItem) {
|
||||
return isZh.value ? item.labelZh : item.labelEn;
|
||||
}
|
||||
|
||||
function downloadUrl(item: DownloadItem) {
|
||||
return `${BASE}/${item.file}`;
|
||||
}
|
||||
|
||||
interface InstallStep {
|
||||
titleZh: string;
|
||||
titleEn: string;
|
||||
stepsZh: string[];
|
||||
stepsEn: string[];
|
||||
}
|
||||
|
||||
const installInstructions = computed<InstallStep[]>(() => {
|
||||
const os = activeOS.value;
|
||||
if (os === 'macos') {
|
||||
return [{
|
||||
titleZh: '安装步骤',
|
||||
titleEn: 'Installation',
|
||||
stepsZh: [
|
||||
'打开下载的 .dmg 文件',
|
||||
'将 AQBot 拖入「应用程序」文件夹',
|
||||
'首次运行时,在「系统设置 → 隐私与安全性」中允许运行',
|
||||
],
|
||||
stepsEn: [
|
||||
'Open the downloaded .dmg file',
|
||||
'Drag AQBot to the Applications folder',
|
||||
'On first launch, allow it in System Settings → Privacy & Security',
|
||||
],
|
||||
}];
|
||||
}
|
||||
if (os === 'windows') {
|
||||
return [
|
||||
{
|
||||
titleZh: '安装版',
|
||||
titleEn: 'Installer',
|
||||
stepsZh: [
|
||||
'运行下载的安装程序',
|
||||
'按向导完成安装',
|
||||
'从开始菜单或桌面快捷方式启动',
|
||||
],
|
||||
stepsEn: [
|
||||
'Run the downloaded installer',
|
||||
'Follow the wizard to complete installation',
|
||||
'Launch from Start Menu or desktop shortcut',
|
||||
],
|
||||
},
|
||||
{
|
||||
titleZh: '绿色免安装版 (Portable)',
|
||||
titleEn: 'Portable',
|
||||
stepsZh: [
|
||||
'解压 .zip 文件到任意目录',
|
||||
'双击 AQBot.exe 即可运行',
|
||||
],
|
||||
stepsEn: [
|
||||
'Extract the .zip file to any directory',
|
||||
'Double-click AQBot.exe to run',
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
return [{
|
||||
titleZh: '安装步骤',
|
||||
titleEn: 'Installation',
|
||||
stepsZh: [
|
||||
'Debian/Ubuntu: sudo dpkg -i AQBot_x.x.x_amd64.deb',
|
||||
'AppImage: chmod +x AQBot_x.x.x_amd64.AppImage && ./AQBot_x.x.x_amd64.AppImage',
|
||||
'RPM: sudo rpm -i AQBot-x.x.x-1.x86_64.rpm',
|
||||
],
|
||||
stepsEn: [
|
||||
'Debian/Ubuntu: sudo dpkg -i AQBot_x.x.x_amd64.deb',
|
||||
'AppImage: chmod +x AQBot_x.x.x_amd64.AppImage && ./AQBot_x.x.x_amd64.AppImage',
|
||||
'RPM: sudo rpm -i AQBot-x.x.x-1.x86_64.rpm',
|
||||
],
|
||||
}];
|
||||
});
|
||||
|
||||
const sysReq = computed(() => {
|
||||
const os = activeOS.value;
|
||||
if (os === 'macos') return isZh.value ? 'macOS 11.0 (Big Sur) 及以上' : 'macOS 11.0 (Big Sur) or later';
|
||||
if (os === 'windows') return isZh.value ? 'Windows 10 (1803) 及以上' : 'Windows 10 (1803) or later';
|
||||
return isZh.value ? '各主流 Linux 发行版' : 'Major Linux distributions';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="download-page">
|
||||
<!-- Version badge -->
|
||||
<div class="version-header">
|
||||
<a class="version-badge" href="https://github.com/AQBot-Desktop/AQBot/releases" target="_blank" rel="noopener">
|
||||
<ClockCircleOutlined />
|
||||
{{ isZh ? '最新发行版本' : 'Latest Release' }}:v{{ VERSION }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- OS Tabs -->
|
||||
<div class="os-tabs">
|
||||
<button
|
||||
v-for="tab in osTabs"
|
||||
:key="tab.id"
|
||||
:class="['os-tab', { active: activeOS === tab.id }]"
|
||||
@click="activeOS = tab.id"
|
||||
>
|
||||
<AppleOutlined v-if="tab.id === 'macos'" class="tab-icon" />
|
||||
<WindowsOutlined v-else-if="tab.id === 'windows'" class="tab-icon" />
|
||||
<svg v-else class="tab-icon" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 448 512" fill="currentColor"><path d="M220.8 123.3c1 .5 1.8 1.7 3 1.7 1.1 0 2.8-.4 2.9-1.5.2-1.4-1.9-2.3-3.2-2.9-1.7-.7-3.9-1-5.5-.1-.4.2-.8.7-.6 1.1.3 1.3 2.3 1.1 3.4 1.7zm-21.9 1.7c1.2 0 2-1.2 3-1.7 1.1-.6 3.1-.4 3.5-1.6.2-.4-.2-.9-.6-1.1-1.6-.9-3.8-.6-5.5.1-1.3.6-3.4 1.5-3.2 2.9.1 1 1.8 1.5 2.8 1.4zM420 403.8c-3.6-4-5.3-11.6-7.2-19.7-1.8-8.1-3.9-16.8-10.5-22.4-1.3-1.1-2.6-2.1-4-2.9-1.3-.8-2.7-1.5-4.1-2 9.2-27.3 5.6-54.5-3.7-79.1-11.4-30.1-31.3-56.4-46.5-74.4-17.1-21.5-33.7-41.9-33.4-72C311.1 85.4 315.7.1 234.8 0 132.4-.2 158 85.4 157.7 130.9c.3 30.4-16.3 51-33.4 72-15.2 18-35.1 44.3-46.5 74.4-9.3 24.6-12.9 51.8-3.7 79.1-1.4.5-2.8 1.2-4.1 2-1.4.8-2.7 1.8-4 2.9-6.6 5.6-8.7 14.3-10.5 22.4-1.9 8.1-3.6 15.7-7.2 19.7-6.3 6.7-7.1 16.5-3.5 22.9 3.6 6.4 11.5 9.5 18.5 6.9 3.6-1.3 6.5-4 9.1-6.5 2.5-2.5 4.9-5 7.9-6.5 5.4-2.8 12.4-2.3 19-1.2 6.8 1.2 13.2 3.1 18.8 1.9 12.2-2.6 16.5-11.1 23.7-16.9.5-.4.4-1.2-.1-1.6-.4-.3-1-.3-1.4.1-3.6 4-10.1 12.6-19.4 14.5-5.1 1-11.1-1-17.5-2.1-6.4-1.2-13.5-1.6-19.4 1.4-3.5 1.8-6.1 4.6-8.7 7.1-2.6 2.6-5.1 4.9-8.2 6-4.3 1.6-9.4-.3-11.7-4.4-2.3-4.1-1.7-10.6 2.6-15.1 4.5-4.9 6.3-13.5 8.2-21.5 1.9-8.1 3.9-16.3 9.6-21.1 2.4-2 5.3-3.2 8.3-3.5 2 12.3 9.2 23.4 19.5 31.1 1.4 1 1 3.6-.5 4.1-5.1 1.6-7.4 6.5-4.8 10.4 2.5 3.7 7.9 4.7 11.6 2.2 3.8-2.5 5.1-7.8 2.6-11.6-.5-.8-1.2-1.4-1.9-1.9 1.4-.5 2.4-1.8 2.1-3.2-.3-1.3-1.7-2.2-3-2.2h-.7c3.4-3.7 6.2-8.1 7.9-13 4.3.3 8.4 2 11.3 5.1 4.4 4.8 5.3 11.7 7.1 18 1.8 6.2 4.5 12.4 10.2 15.7 2.5 1.4 5.6 2 8.5 1 2.5-.9 4.3-3.1 5-5.7.4-1.5.2-3.1-.4-4.5-1.4-3.2-4.6-5-7.6-6.6-3-1.5-6.2-3-8-5.8-1.6-2.5-2-5.6-1.2-8.5.6-2.2 2.1-4.2 4.2-5 3.2-1.2 6.7.3 8.5 3.1 1 1.5 1.4 3.4 1.2 5.2.2.5.4 1 .5 1.5.3 1 .5 2.1.5 3.2 0 3.5-1.3 6.8-3.5 9.3 2.4 1.7 5.2 2.7 8.2 2.7 4.4 0 8.5-2.1 11.1-5.5 2.8-3.7 3.5-8.6 1.8-12.9z"/></svg>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Download buttons -->
|
||||
<div class="download-section">
|
||||
<div class="download-grid">
|
||||
<a
|
||||
v-for="item in currentDownloads"
|
||||
:key="item.file"
|
||||
:href="downloadUrl(item)"
|
||||
:class="['dl-btn', item.primary ? 'dl-primary' : 'dl-secondary']"
|
||||
>
|
||||
<AppleOutlined v-if="activeOS === 'macos'" class="btn-icon" />
|
||||
<WindowsOutlined v-else-if="activeOS === 'windows'" class="btn-icon" />
|
||||
<svg v-else class="btn-icon" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 448 512" fill="currentColor"><path d="M220.8 123.3c1 .5 1.8 1.7 3 1.7 1.1 0 2.8-.4 2.9-1.5.2-1.4-1.9-2.3-3.2-2.9-1.7-.7-3.9-1-5.5-.1-.4.2-.8.7-.6 1.1.3 1.3 2.3 1.1 3.4 1.7zm-21.9 1.7c1.2 0 2-1.2 3-1.7 1.1-.6 3.1-.4 3.5-1.6.2-.4-.2-.9-.6-1.1-1.6-.9-3.8-.6-5.5.1-1.3.6-3.4 1.5-3.2 2.9.1 1 1.8 1.5 2.8 1.4zM420 403.8c-3.6-4-5.3-11.6-7.2-19.7-1.8-8.1-3.9-16.8-10.5-22.4-1.3-1.1-2.6-2.1-4-2.9-1.3-.8-2.7-1.5-4.1-2 9.2-27.3 5.6-54.5-3.7-79.1-11.4-30.1-31.3-56.4-46.5-74.4-17.1-21.5-33.7-41.9-33.4-72C311.1 85.4 315.7.1 234.8 0 132.4-.2 158 85.4 157.7 130.9c.3 30.4-16.3 51-33.4 72-15.2 18-35.1 44.3-46.5 74.4-9.3 24.6-12.9 51.8-3.7 79.1-1.4.5-2.8 1.2-4.1 2-1.4.8-2.7 1.8-4 2.9-6.6 5.6-8.7 14.3-10.5 22.4-1.9 8.1-3.6 15.7-7.2 19.7-6.3 6.7-7.1 16.5-3.5 22.9 3.6 6.4 11.5 9.5 18.5 6.9 3.6-1.3 6.5-4 9.1-6.5 2.5-2.5 4.9-5 7.9-6.5 5.4-2.8 12.4-2.3 19-1.2 6.8 1.2 13.2 3.1 18.8 1.9 12.2-2.6 16.5-11.1 23.7-16.9.5-.4.4-1.2-.1-1.6-.4-.3-1-.3-1.4.1-3.6 4-10.1 12.6-19.4 14.5-5.1 1-11.1-1-17.5-2.1-6.4-1.2-13.5-1.6-19.4 1.4-3.5 1.8-6.1 4.6-8.7 7.1-2.6 2.6-5.1 4.9-8.2 6-4.3 1.6-9.4-.3-11.7-4.4-2.3-4.1-1.7-10.6 2.6-15.1 4.5-4.9 6.3-13.5 8.2-21.5 1.9-8.1 3.9-16.3 9.6-21.1 2.4-2 5.3-3.2 8.3-3.5 2 12.3 9.2 23.4 19.5 31.1 1.4 1 1 3.6-.5 4.1-5.1 1.6-7.4 6.5-4.8 10.4 2.5 3.7 7.9 4.7 11.6 2.2 3.8-2.5 5.1-7.8 2.6-11.6-.5-.8-1.2-1.4-1.9-1.9 1.4-.5 2.4-1.8 2.1-3.2-.3-1.3-1.7-2.2-3-2.2h-.7c3.4-3.7 6.2-8.1 7.9-13 4.3.3 8.4 2 11.3 5.1 4.4 4.8 5.3 11.7 7.1 18 1.8 6.2 4.5 12.4 10.2 15.7 2.5 1.4 5.6 2 8.5 1 2.5-.9 4.3-3.1 5-5.7.4-1.5.2-3.1-.4-4.5-1.4-3.2-4.6-5-7.6-6.6-3-1.5-6.2-3-8-5.8-1.6-2.5-2-5.6-1.2-8.5.6-2.2 2.1-4.2 4.2-5 3.2-1.2 6.7.3 8.5 3.1 1 1.5 1.4 3.4 1.2 5.2.2.5.4 1 .5 1.5.3 1 .5 2.1.5 3.2 0 3.5-1.3 6.8-3.5 9.3 2.4 1.7 5.2 2.7 8.2 2.7 4.4 0 8.5-2.1 11.1-5.5 2.8-3.7 3.5-8.6 1.8-12.9z"/></svg>
|
||||
<span>{{ itemLabel(item) }}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- System requirement -->
|
||||
<div class="sys-req">
|
||||
<span class="sys-req-label">{{ isZh ? '系统要求' : 'System Requirements' }}:</span>
|
||||
{{ sysReq }}
|
||||
</div>
|
||||
|
||||
<!-- GitHub Releases link -->
|
||||
<a
|
||||
class="releases-link"
|
||||
href="https://github.com/AQBot-Desktop/AQBot/releases"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ isZh ? '前往 GitHub Releases 下载更多版本' : 'View all versions on GitHub Releases' }}
|
||||
<LinkOutlined />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Installation instructions -->
|
||||
<div class="install-section">
|
||||
<h3 class="section-title">{{ isZh ? '安装说明' : 'Installation' }}</h3>
|
||||
<div v-for="(inst, idx) in installInstructions" :key="idx" class="install-block">
|
||||
<h4 v-if="installInstructions.length > 1" class="install-subtitle">
|
||||
{{ isZh ? inst.titleZh : inst.titleEn }}
|
||||
</h4>
|
||||
<ol class="install-steps">
|
||||
<li v-for="(step, si) in (isZh ? inst.stepsZh : inst.stepsEn)" :key="si">
|
||||
{{ step }}
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.download-page {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: 48px 24px 64px;
|
||||
}
|
||||
|
||||
/* Version header */
|
||||
.version-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.version-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-brand-1);
|
||||
background: var(--vp-c-brand-soft);
|
||||
padding: 6px 16px;
|
||||
border-radius: 20px;
|
||||
letter-spacing: 0.02em;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.version-badge:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* OS Tabs */
|
||||
.os-tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 32px;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.os-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 24px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-2);
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.os-tab:hover {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.os-tab.active {
|
||||
color: var(--vp-c-brand-1);
|
||||
border-bottom-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.os-tab.active .tab-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Download section */
|
||||
.download-section {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.download-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.dl-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 0 24px;
|
||||
height: 52px;
|
||||
border-radius: 12px;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.dl-btn:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
color: var(--vp-c-text-1);
|
||||
background: var(--vp-c-brand-soft);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.dl-primary {
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.dl-secondary {
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
flex-shrink: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* System requirements */
|
||||
.sys-req {
|
||||
margin-top: 16px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.sys-req-label {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
/* Releases link */
|
||||
.releases-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-top: 16px;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-brand-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.releases-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Installation section */
|
||||
.install-section {
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
padding-top: 32px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.install-block {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.install-subtitle {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.install-steps {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.install-steps li {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
/* Mobile responsive */
|
||||
@media (max-width: 640px) {
|
||||
.download-page {
|
||||
padding: 32px 16px 48px;
|
||||
}
|
||||
|
||||
.os-tabs {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.os-tab {
|
||||
padding: 10px 16px;
|
||||
font-size: 14px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.dl-btn {
|
||||
padding: 0 16px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.dl-primary {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,166 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useData } from 'vitepress';
|
||||
import {
|
||||
RobotOutlined,
|
||||
ThunderboltOutlined,
|
||||
ApiOutlined,
|
||||
CloudServerOutlined,
|
||||
BookOutlined,
|
||||
SearchOutlined,
|
||||
EditOutlined,
|
||||
DesktopOutlined,
|
||||
LockOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
const iconMap: Record<string, any> = {
|
||||
robot: RobotOutlined,
|
||||
thunderbolt: ThunderboltOutlined,
|
||||
api: ApiOutlined,
|
||||
'cloud-server': CloudServerOutlined,
|
||||
book: BookOutlined,
|
||||
search: SearchOutlined,
|
||||
edit: EditOutlined,
|
||||
desktop: DesktopOutlined,
|
||||
lock: LockOutlined,
|
||||
};
|
||||
|
||||
const { frontmatter } = useData();
|
||||
const features = computed(() => frontmatter.value.features || []);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="features-grid" v-if="features.length">
|
||||
<div class="features-container">
|
||||
<div
|
||||
v-for="(feature, index) in features"
|
||||
:key="index"
|
||||
class="feature-card"
|
||||
>
|
||||
<div class="card-inner">
|
||||
<div class="icon-wrapper">
|
||||
<component
|
||||
:is="iconMap[feature.icon] || RobotOutlined"
|
||||
class="feature-icon"
|
||||
/>
|
||||
</div>
|
||||
<h3 class="feature-title">{{ feature.title }}</h3>
|
||||
<p class="feature-details">{{ feature.details }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.features-grid {
|
||||
max-width: 1152px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px 48px;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.feature-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 12px;
|
||||
padding: 1px;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
transparent 0%,
|
||||
transparent 100%
|
||||
);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
opacity: 0;
|
||||
transition: opacity 0.35s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
box-shadow:
|
||||
0 0 0 1px var(--vp-c-brand-1),
|
||||
0 4px 24px rgba(48, 151, 49, 0.15),
|
||||
0 0 48px rgba(48, 151, 49, 0.08);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.dark .feature-card:hover {
|
||||
box-shadow:
|
||||
0 0 0 1px var(--vp-c-brand-1),
|
||||
0 4px 24px rgba(63, 186, 64, 0.2),
|
||||
0 0 48px rgba(63, 186, 64, 0.1);
|
||||
}
|
||||
|
||||
.card-inner {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
background: var(--vp-c-default-soft);
|
||||
margin-bottom: 16px;
|
||||
transition: all 0.35s ease;
|
||||
}
|
||||
|
||||
.feature-card:hover .icon-wrapper {
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 24px;
|
||||
color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.feature-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.feature-details {
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
margin: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.features-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.features-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.features-grid {
|
||||
padding: 0 16px 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultTheme from 'vitepress/theme';
|
||||
import { useData } from 'vitepress';
|
||||
import DownloadBar from './DownloadBar.vue';
|
||||
import ImageCarousel from './ImageCarousel.vue';
|
||||
import FeaturesGrid from './FeaturesGrid.vue';
|
||||
|
||||
const { Layout } = DefaultTheme;
|
||||
const { frontmatter } = useData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<template #home-hero-info-after>
|
||||
<div v-if="frontmatter?.layout === 'home'" class="hero-actions-custom">
|
||||
<DownloadBar />
|
||||
</div>
|
||||
</template>
|
||||
<template #home-features-before>
|
||||
<div v-if="frontmatter?.layout === 'home'">
|
||||
<ImageCarousel />
|
||||
</div>
|
||||
</template>
|
||||
<template #home-features-after>
|
||||
<div v-if="frontmatter?.layout === 'home'">
|
||||
<FeaturesGrid />
|
||||
</div>
|
||||
</template>
|
||||
<template #layout-bottom>
|
||||
<footer class="site-footer">
|
||||
<p>© 2026 AQBot</p>
|
||||
</footer>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hero-actions-custom {
|
||||
width: 100%;
|
||||
}
|
||||
.site-footer {
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
color: var(--vp-c-text-3);
|
||||
font-size: 14px;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
.site-footer p {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,175 @@
|
||||
<script setup lang="ts">
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue';
|
||||
import { Autoplay, Pagination, Navigation } from 'swiper/modules';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-vue-next';
|
||||
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/pagination';
|
||||
import 'swiper/css/navigation';
|
||||
|
||||
const modules = [Autoplay, Pagination, Navigation];
|
||||
|
||||
const screenshots = [
|
||||
'/screenshots/s1-0412.png',
|
||||
'/screenshots/s2-0412.png',
|
||||
'/screenshots/s3-0412.png',
|
||||
'/screenshots/s4-0412.png',
|
||||
'/screenshots/s5-0412.png',
|
||||
'/screenshots/s6-0412.png',
|
||||
'/screenshots/s7-0412.png',
|
||||
'/screenshots/s8-0412.png',
|
||||
'/screenshots/s9-0412.png',
|
||||
'/screenshots/s10-0412.png',
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="carousel-section">
|
||||
<Swiper
|
||||
:modules="modules"
|
||||
:slides-per-view="1"
|
||||
:space-between="16"
|
||||
:loop="true"
|
||||
:autoplay="{ delay: 4000, disableOnInteraction: false, pauseOnMouseEnter: true }"
|
||||
:pagination="{ clickable: true }"
|
||||
:navigation="{ nextEl: '.carousel-next', prevEl: '.carousel-prev' }"
|
||||
class="screenshots-swiper"
|
||||
>
|
||||
<SwiperSlide v-for="(src, idx) in screenshots" :key="idx">
|
||||
<div class="slide-wrapper">
|
||||
<img :src="src" :alt="`AQBot Screenshot ${idx + 1}`" loading="lazy" />
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
<button class="carousel-nav carousel-prev" aria-label="Previous slide">
|
||||
<ChevronLeft :size="24" />
|
||||
</button>
|
||||
<button class="carousel-nav carousel-next" aria-label="Next slide">
|
||||
<ChevronRight :size="24" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.carousel-section {
|
||||
position: relative;
|
||||
max-width: 960px;
|
||||
margin: 40px auto 24px;
|
||||
padding: 0 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.carousel-section {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.carousel-section {
|
||||
padding: 0 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.screenshots-swiper {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.slide-wrapper {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.1);
|
||||
background: var(--vp-c-bg-soft);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.slide-wrapper:hover {
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.dark .slide-wrapper {
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.dark .slide-wrapper:hover {
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.slide-wrapper img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Navigation arrows */
|
||||
.carousel-nav {
|
||||
position: absolute;
|
||||
top: calc(50% - 20px);
|
||||
transform: translateY(-50%);
|
||||
z-index: 10;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.carousel-nav:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
color: var(--vp-c-brand-1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.dark .carousel-nav {
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.carousel-prev {
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
.carousel-next {
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.carousel-prev { left: 16px; }
|
||||
.carousel-next { right: 16px; }
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.carousel-prev { left: 28px; }
|
||||
.carousel-next { right: 28px; }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.carousel-nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Swiper pagination bullets */
|
||||
:deep(.swiper-pagination-bullet) {
|
||||
background: var(--vp-c-text-3);
|
||||
opacity: 0.4;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
:deep(.swiper-pagination-bullet-active) {
|
||||
background: var(--vp-c-brand-1);
|
||||
opacity: 1;
|
||||
width: 24px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,209 @@
|
||||
:root {
|
||||
--vp-c-brand-1: #309731;
|
||||
--vp-c-brand-2: #27802a;
|
||||
--vp-c-brand-3: #1f6922;
|
||||
--vp-c-brand-soft: rgba(48, 151, 49, 0.14);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-c-brand-1: #3fba40;
|
||||
--vp-c-brand-2: #309731;
|
||||
--vp-c-brand-3: #27802a;
|
||||
--vp-c-brand-soft: rgba(63, 186, 64, 0.16);
|
||||
}
|
||||
|
||||
/* Hero name gradient with brand green */
|
||||
:root {
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #309731 30%, #56c457);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #3fba40 30%, #7ade7b);
|
||||
}
|
||||
|
||||
/* Hero: center text, hide image area */
|
||||
.VPHero .VPImage,
|
||||
.VPHero .image-container,
|
||||
.VPHero .image {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Override default hero layout for centered text-only hero */
|
||||
.VPHero .container {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.VPHero .main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.VPHero .heading {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.VPHero .name,
|
||||
.VPHero .text {
|
||||
margin: 0 auto !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.VPHero .tagline {
|
||||
margin: 0 auto !important;
|
||||
text-align: center !important;
|
||||
max-width: 576px !important;
|
||||
}
|
||||
|
||||
/* Remove default hero actions (we use custom ones) */
|
||||
.VPHero .actions {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide default VitePress features (we render custom FeaturesGrid) */
|
||||
.VPFeatures {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Reduce hero vertical space */
|
||||
@media (min-width: 960px) {
|
||||
.VPHero {
|
||||
padding-top: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 48px) !important;
|
||||
padding-bottom: 32px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nav icons via ::before pseudo-elements */
|
||||
.VPNavBarMenuLink[href="/"],
|
||||
.VPNavBarMenuLink[href="/zh/"],
|
||||
.VPNavBarMenuLink[href="/zh-tw/"],
|
||||
.VPNavBarMenuLink[href="/ja/"],
|
||||
.VPNavBarMenuLink[href="/ko/"],
|
||||
.VPNavBarMenuLink[href="/fr/"],
|
||||
.VPNavBarMenuLink[href="/de/"],
|
||||
.VPNavBarMenuLink[href="/es/"],
|
||||
.VPNavBarMenuLink[href="/ru/"],
|
||||
.VPNavBarMenuLink[href="/hi/"],
|
||||
.VPNavBarMenuLink[href="/ar/"] {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
.VPNavBarMenuLink[href="/"]::before,
|
||||
.VPNavBarMenuLink[href="/zh/"]::before,
|
||||
.VPNavBarMenuLink[href="/zh-tw/"]::before,
|
||||
.VPNavBarMenuLink[href="/ja/"]::before,
|
||||
.VPNavBarMenuLink[href="/ko/"]::before,
|
||||
.VPNavBarMenuLink[href="/fr/"]::before,
|
||||
.VPNavBarMenuLink[href="/de/"]::before,
|
||||
.VPNavBarMenuLink[href="/es/"]::before,
|
||||
.VPNavBarMenuLink[href="/ru/"]::before,
|
||||
.VPNavBarMenuLink[href="/hi/"]::before,
|
||||
.VPNavBarMenuLink[href="/ar/"]::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
background-color: var(--vp-c-text-2);
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
transition: background-color 0.25s;
|
||||
}
|
||||
|
||||
/* Home icon (nav item 1) */
|
||||
.VPNavBarMenuLink[href="/"]::before,
|
||||
.VPNavBarMenuLink[href="/zh/"]::before,
|
||||
.VPNavBarMenuLink[href="/zh-tw/"]::before,
|
||||
.VPNavBarMenuLink[href="/ja/"]::before,
|
||||
.VPNavBarMenuLink[href="/ko/"]::before,
|
||||
.VPNavBarMenuLink[href="/fr/"]::before,
|
||||
.VPNavBarMenuLink[href="/de/"]::before,
|
||||
.VPNavBarMenuLink[href="/es/"]::before,
|
||||
.VPNavBarMenuLink[href="/ru/"]::before,
|
||||
.VPNavBarMenuLink[href="/hi/"]::before,
|
||||
.VPNavBarMenuLink[href="/ar/"]::before {
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M946.5 505L560.1 118.8l-25.9-25.9a31.5 31.5 0 00-44.4 0L77.5 505a63.9 63.9 0 00-18.8 46c.4 35.2 29.7 63.3 64.9 63.3h42.5V940h691.8V614.3h43.4c17.1 0 33.2-6.7 45.3-18.8a63.6 63.6 0 0018.7-45.3c0-17-6.7-33.1-18.8-45.2zM568 868H456V664h112v204zm217.9-325.7V868H632V640c0-22.1-17.9-40-40-40H432c-22.1 0-40 17.9-40 40v228H238.1V542.3h-96l370-369.7 23.1 23.1L882 542.3h-96.1z'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M946.5 505L560.1 118.8l-25.9-25.9a31.5 31.5 0 00-44.4 0L77.5 505a63.9 63.9 0 00-18.8 46c.4 35.2 29.7 63.3 64.9 63.3h42.5V940h691.8V614.3h43.4c17.1 0 33.2-6.7 45.3-18.8a63.6 63.6 0 0018.7-45.3c0-17-6.7-33.1-18.8-45.2zM568 868H456V664h112v204zm217.9-325.7V868H632V640c0-22.1-17.9-40-40-40H432c-22.1 0-40 17.9-40 40v228H238.1V542.3h-96l370-369.7 23.1 23.1L882 542.3h-96.1z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Features icon (nav item 2) */
|
||||
.VPNavBarMenuLink[href*="/features"]::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
background-color: var(--vp-c-text-2);
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
transition: background-color 0.25s;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Download icon (nav item 3) */
|
||||
.VPNavBarMenuLink[href*="/download"]::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
background-color: var(--vp-c-text-2);
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
transition: background-color 0.25s;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Docs icon (nav item 4) */
|
||||
.VPNavBarMenuLink[href*="/guide/"]::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
background-color: var(--vp-c-text-2);
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
transition: background-color 0.25s;
|
||||
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M928 161H699.2c-49.1 0-97.1 14.1-138.4 40.7L512 233l-48.8-31.3A255.2 255.2 0 00324.8 161H96c-17.7 0-32 14.3-32 32v568c0 17.7 14.3 32 32 32h228.8c49.1 0 97.1 14.1 138.4 40.7l44.4 28.6c1.3.8 2.8 1.3 4.3 1.3s3-.4 4.3-1.3l44.4-28.6c41.3-26.6 89.3-40.7 138.4-40.7H928c17.7 0 32-14.3 32-32V193c0-17.7-14.3-32-32-32zM324.8 721H136V233h188.8c35.4 0 69.8 10.1 99.5 29.2l48.8 31.3 6.9 4.5v462c-47.6-25.6-100.8-39-155.2-39zm563.2 0H699.2c-54.4 0-107.6 13.4-155.2 39V298l6.9-4.5 48.8-31.3c29.7-19.1 64.1-29.2 99.5-29.2H888v488z'/%3E%3C/svg%3E");
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M928 161H699.2c-49.1 0-97.1 14.1-138.4 40.7L512 233l-48.8-31.3A255.2 255.2 0 00324.8 161H96c-17.7 0-32 14.3-32 32v568c0 17.7 14.3 32 32 32h228.8c49.1 0 97.1 14.1 138.4 40.7l44.4 28.6c1.3.8 2.8 1.3 4.3 1.3s3-.4 4.3-1.3l44.4-28.6c41.3-26.6 89.3-40.7 138.4-40.7H928c17.7 0 32-14.3 32-32V193c0-17.7-14.3-32-32-32zM324.8 721H136V233h188.8c35.4 0 69.8 10.1 99.5 29.2l48.8 31.3 6.9 4.5v462c-47.6-25.6-100.8-39-155.2-39zm563.2 0H699.2c-54.4 0-107.6 13.4-155.2 39V298l6.9-4.5 48.8-31.3c29.7-19.1 64.1-29.2 99.5-29.2H888v488z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Features/download/docs links also need flex layout */
|
||||
.VPNavBarMenuLink[href*="/features"],
|
||||
.VPNavBarMenuLink[href*="/download"],
|
||||
.VPNavBarMenuLink[href*="/guide/"] {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* Nav icon color follows link text: default muted, active = brand color */
|
||||
.VPNavBarMenuLink:hover::before,
|
||||
.VPNavBarMenuLink.active::before {
|
||||
background-color: var(--vp-c-brand-1) !important;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import DefaultTheme from 'vitepress/theme';
|
||||
import { useRouter, inBrowser } from 'vitepress';
|
||||
import { onMounted } from 'vue';
|
||||
import HomeLayout from './HomeLayout.vue';
|
||||
import DownloadHero from './DownloadHero.vue';
|
||||
import './custom.css';
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
Layout: HomeLayout,
|
||||
enhanceApp({ app }) {
|
||||
app.component('DownloadHero', DownloadHero);
|
||||
},
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
if (!inBrowser) return;
|
||||
const path = window.location.pathname;
|
||||
if (path !== '/') return;
|
||||
const lang = navigator.language || navigator.languages?.[0] || '';
|
||||
if (/^zh/i.test(lang)) {
|
||||
router.go('/zh/');
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user