|
|
|
|
@@ -1,13 +1,14 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import type { AppInfo } from '~/types'
|
|
|
|
|
|
|
|
|
|
import { apps as appsData, categories as categoriesData } from '~/data/apps'
|
|
|
|
|
|
|
|
|
|
const { t, locale, setLocale } = useI18n()
|
|
|
|
|
const colorMode = useColorMode()
|
|
|
|
|
|
|
|
|
|
// 获取应用列表
|
|
|
|
|
const { data: appsData } = await useFetch('/api/apps')
|
|
|
|
|
const apps = computed(() => appsData.value?.apps || [])
|
|
|
|
|
const categories = computed(() => appsData.value?.categories || [])
|
|
|
|
|
// 直接使用数据文件
|
|
|
|
|
const apps = computed(() => appsData)
|
|
|
|
|
const categories = computed(() => categoriesData)
|
|
|
|
|
|
|
|
|
|
// 当前选中的分类
|
|
|
|
|
const selectedCategory = ref('all')
|
|
|
|
|
@@ -105,10 +106,10 @@ useHead({
|
|
|
|
|
<header class="sticky top-0 z-50">
|
|
|
|
|
<div class="flex items-center justify-between py-4">
|
|
|
|
|
<div class="flex items-center gap-3 group">
|
|
|
|
|
<div class="size-10 rounded-xl bg-linear-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-xl relative overflow-hidden transition-all duration-300 group-hover:scale-110 animate-gradient shadow-lg shadow-blue-500/50">
|
|
|
|
|
<div class="absolute inset-0 bg-linear-to-tr from-white/0 via-white/20 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></div>
|
|
|
|
|
<div class="size-10 rounded-xl bg-linear-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-xl relative overflow-hidden shadow-lg shadow-blue-500/50">
|
|
|
|
|
<div class="absolute inset-0 bg-linear-to-tr from-white/0 via-white/20 to-white/0 -translate-x-full group-hover:translate-x-full transition-transform duration-700"></div>
|
|
|
|
|
<div class="absolute -inset-1 bg-blue-400/30 rounded-xl blur-md opacity-0 group-hover:opacity-100 animate-pulse-ring"></div>
|
|
|
|
|
<span class="relative z-10 animate-pulse-subtle">R</span>
|
|
|
|
|
<span class="relative z-10">R</span>
|
|
|
|
|
</div>
|
|
|
|
|
<h1 class="text-xl font-bold bg-linear-to-r from-gray-900 via-primary-600 to-purple-600 dark:from-white dark:via-primary-400 dark:to-purple-400 bg-clip-text text-transparent animate-gradient">
|
|
|
|
|
{{ t('appName') }}
|
|
|
|
|
@@ -164,26 +165,24 @@ useHead({
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Apps Grid -->
|
|
|
|
|
<div v-if="filteredApps.length > 0" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 perspective-1000">
|
|
|
|
|
<div v-if="filteredApps.length > 0" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(app, index) in filteredApps"
|
|
|
|
|
:key="app.id"
|
|
|
|
|
class="group relative animate-fade-in-up transform-gpu"
|
|
|
|
|
class="group relative animate-fade-in-up"
|
|
|
|
|
>
|
|
|
|
|
<UCard
|
|
|
|
|
class="cursor-pointer backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 transition-all duration-500 hover:shadow-2xl hover:shadow-primary-500/20 hover:-translate-y-2 hover:rotate-y-2 active:scale-95 active:shadow-lg active:shadow-primary-500/40 relative overflow-hidden touch-manipulation"
|
|
|
|
|
class="cursor-pointer backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 duration-500 hover:shadow-2xl hover:shadow-primary-500/20 hover:-translate-y-2 hover:rotate-y-2 active:scale-95 active:shadow-lg active:shadow-primary-500/40 relative overflow-hidden"
|
|
|
|
|
@click="openAppDetail(app)"
|
|
|
|
|
>
|
|
|
|
|
<!-- 内部发光效果 -->
|
|
|
|
|
<div class="absolute inset-0 bg-linear-to-br from-primary-500/5 via-transparent to-purple-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
|
|
|
|
<div class="absolute inset-0 bg-linear-to-br from-primary-500/5 to-purple-500/5"></div>
|
|
|
|
|
|
|
|
|
|
<div class="flex items-start gap-4 relative z-10">
|
|
|
|
|
<!-- App Icon -->
|
|
|
|
|
<div class="size-16 rounded-2xl bg-linear-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-2xl shrink-0 shadow-lg shadow-blue-500/50 relative overflow-hidden group-hover:shadow-2xl group-hover:shadow-blue-500/60 transition-all duration-500 group-hover:scale-110 group-hover:rotate-3 group-active:scale-105 group-active:rotate-1 animate-float-subtle p-2">
|
|
|
|
|
<div class="size-16 rounded-2xl bg-linear-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-2xl shrink-0 shadow-lg shadow-blue-500/50 relative overflow-hidden group-hover:shadow-2xl group-hover:shadow-blue-500/60 transition-all duration-500 group-hover:scale-110 group-hover:rotate-3 group-active:scale-105 group-active:rotate-1 p-2">
|
|
|
|
|
<!-- 动态发光效果 -->
|
|
|
|
|
<div class="absolute inset-0 bg-linear-to-tr from-white/0 via-white/30 to-white/0 translate-x-[-100%] group-hover:translate-x-full group-active:translate-x-[50%] transition-transform duration-700"></div>
|
|
|
|
|
<!-- 脉冲光环 -->
|
|
|
|
|
<div class="absolute -inset-2 bg-blue-400/30 rounded-2xl blur-md opacity-0 group-hover:opacity-100 animate-pulse-ring"></div>
|
|
|
|
|
<img :src="app.icon" :alt="app.name" class="size-full object-contain relative z-10 rounded-lg transition-all duration-300 group-active:scale-95 group-hover:rotate-[-3deg]" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
@@ -211,7 +210,7 @@ useHead({
|
|
|
|
|
label="iOS"
|
|
|
|
|
size="lg"
|
|
|
|
|
block
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 touch-manipulation relative overflow-hidden group/btn"
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 relative overflow-hidden group/btn"
|
|
|
|
|
@click.stop="(e) => handleDownload(app, 'ios', e)"
|
|
|
|
|
>
|
|
|
|
|
</UButton>
|
|
|
|
|
@@ -221,7 +220,7 @@ useHead({
|
|
|
|
|
label="Android"
|
|
|
|
|
size="lg"
|
|
|
|
|
block
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 touch-manipulation relative overflow-hidden group/btn"
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 relative overflow-hidden group/btn"
|
|
|
|
|
@click.stop="(e) => handleDownload(app, 'android', e)"
|
|
|
|
|
>
|
|
|
|
|
</UButton>
|
|
|
|
|
@@ -231,7 +230,7 @@ useHead({
|
|
|
|
|
label="Web"
|
|
|
|
|
size="lg"
|
|
|
|
|
block
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 touch-manipulation relative overflow-hidden group/btn"
|
|
|
|
|
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-xl active:shadow-blue-500/60 relative overflow-hidden group/btn"
|
|
|
|
|
@click.stop="(e) => handleDownload(app, 'h5', e)"
|
|
|
|
|
>
|
|
|
|
|
</UButton>
|
|
|
|
|
|