feat: 添加应用配置和动画效果,优化首页和应用详情页面样式

This commit is contained in:
2026-01-02 23:40:52 +07:00
parent cedb6cc1a5
commit 6d61715407
7 changed files with 350 additions and 396 deletions

View File

@@ -56,8 +56,19 @@ useHead({
</script>
<template>
<div v-if="app" class="min-h-screen bg-gray-50 dark:bg-gray-900">
<UContainer>
<div v-if="app" class="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-blue-50/30 to-purple-50/30 dark:from-gray-950 dark:via-blue-950/20 dark:to-purple-950/20">
<!-- 科技感网格背景 -->
<div class="fixed inset-0 opacity-30 dark:opacity-20 pointer-events-none">
<div class="absolute inset-0" style="background-image: linear-gradient(rgba(99, 102, 241, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(99, 102, 241, 0.1) 1px, transparent 1px); background-size: 50px 50px;"></div>
</div>
<!-- 动态发光球体背景 -->
<div class="fixed inset-0 pointer-events-none overflow-hidden">
<div class="absolute top-1/4 -left-48 w-96 h-96 bg-primary-500/20 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute bottom-1/4 -right-48 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl animate-pulse" style="animation-delay: 1s;"></div>
</div>
<UContainer class="relative z-10">
<!-- Header -->
<header class="sticky top-0 z-50">
<div class="flex items-center gap-4 py-4">
@@ -65,20 +76,25 @@ useHead({
icon="i-heroicons-arrow-left"
color="neutral"
variant="ghost"
class="hover:scale-110 transition-transform duration-300"
@click="goBack"
/>
<h1 class="text-xl font-bold text-gray-900 dark:text-white">
<h1 class="text-xl font-bold bg-gradient-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">
{{ app.name }}
</h1>
</div>
</header>
<!-- Main Content -->
<div class="py-8">
<div class="py-8 animate-fade-in">
<!-- App Header -->
<div class="flex items-start gap-6 mb-8">
<div class="size-24 rounded-3xl bg-linear-to-br from-primary-500 to-primary-600 flex items-center justify-center text-white font-bold text-4xl shrink-0 shadow-xl">
{{ app.name.charAt(0) }}
<div class="flex items-start gap-6 mb-8 group">
<div class="relative">
<div class="absolute -inset-2 bg-gradient-to-r from-primary-500 via-purple-500 to-blue-500 rounded-3xl opacity-50 blur-xl group-hover:opacity-100 transition-all duration-500 animate-pulse"></div>
<div class="size-24 rounded-3xl bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-4xl shrink-0 shadow-2xl shadow-blue-500/50 relative overflow-hidden group-hover:scale-110 transition-all duration-500">
<div class="absolute inset-0 bg-gradient-to-tr from-white/0 via-white/30 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></div>
<span class="relative z-10">{{ app.name.charAt(0) }}</span>
</div>
</div>
<div class="flex-1">
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-2">
@@ -97,120 +113,148 @@ useHead({
<!-- Download Buttons -->
<div class="grid md:grid-cols-3 gap-4 mb-8">
<UButton
v-if="app.downloads.ios"
icon="i-heroicons-device-phone-mobile"
size="xl"
block
@click="handleDownload('ios')"
>
<div v-if="app.downloads.ios" class="relative group">
<div class="absolute -inset-1 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UButton
icon="i-heroicons-device-phone-mobile"
size="xl"
block
class="relative transition-all duration-300 hover:shadow-2xl hover:shadow-blue-500/50 hover:-translate-y-2"
@click="handleDownload('ios')"
>
<div class="text-left w-full">
<div class="font-semibold text-base">iOS</div>
<div v-if="app.size?.ios" class="text-xs opacity-80">
{{ app.size.ios }}
</div>
</div>
</UButton>
<UButton
v-if="app.downloads.android"
icon="i-heroicons-device-tablet"
size="xl"
block
@click="handleDownload('android')"
>
</UButton>
</div>
<div v-if="app.downloads.android" class="relative group">
<div class="absolute -inset-1 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UButton
icon="i-heroicons-device-tablet"
size="xl"
block
class="relative transition-all duration-300 hover:shadow-2xl hover:shadow-blue-500/50 hover:-translate-y-2"
@click="handleDownload('android')"
>
<div class="text-left w-full">
<div class="font-semibold text-base">Android</div>
<div v-if="app.size?.android" class="text-xs opacity-80">
{{ app.size.android }}
</div>
</div>
</UButton>
<UButton
v-if="app.downloads.h5"
icon="i-heroicons-globe-alt"
size="xl"
block
@click="handleDownload('h5')"
>
<div class="text-left w-full">
<div class="font-semibold text-base">Web</div>
<div class="text-xs opacity-80">
PWA
</UButton>
</div>
<div v-if="app.downloads.h5" class="relative group">
<div class="absolute -inset-1 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UButton
icon="i-heroicons-globe-alt"
size="xl"
block
class="relative transition-all duration-300 hover:shadow-2xl hover:shadow-blue-500/50 hover:-translate-y-2"
@click="handleDownload('h5')"
>
<div class="text-left w-full">
<div class="font-semibold text-base">Web</div>
<div class="text-xs opacity-80">
PWA
</div>
</div>
</div>
</UButton>
</UButton>
</div>
</div>
<!-- Stats -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
<UCard>
<div class="text-center">
<div class="text-3xl font-bold text-primary-500">
{{ app.stats.total.toLocaleString() }}
<div class="relative group">
<div class="absolute -inset-0.5 bg-gradient-to-r from-primary-500 to-purple-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-primary-500/20 transition-all duration-500 hover:-translate-y-1">
<div class="text-center">
<div class="text-3xl font-bold bg-gradient-to-r from-primary-500 to-purple-500 bg-clip-text text-transparent">
{{ app.stats.total.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
{{ locale === 'zh-CN' ? '总下载' : 'Total Downloads' }}
</div>
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
{{ locale === 'zh-CN' ? '总下载' : 'Total Downloads' }}
</UCard>
</div>
<div class="relative group">
<div class="absolute -inset-0.5 bg-gradient-to-r from-purple-500 to-pink-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-purple-500/20 transition-all duration-500 hover:-translate-y-1">
<div class="text-center">
<div class="text-3xl font-bold bg-gradient-to-r from-purple-500 to-pink-500 bg-clip-text text-transparent">
{{ app.stats.today.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
{{ locale === 'zh-CN' ? '今日下载' : 'Today' }}
</div>
</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-3xl font-bold text-primary-500">
{{ app.stats.today.toLocaleString() }}
</UCard>
</div>
<div class="relative group">
<div class="absolute -inset-0.5 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-blue-500/20 transition-all duration-500 hover:-translate-y-1">
<div class="text-center">
<div class="text-3xl font-bold bg-gradient-to-r from-blue-500 to-cyan-500 bg-clip-text text-transparent">
{{ app.stats.ios.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
iOS
</div>
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
{{ locale === 'zh-CN' ? '今日下载' : 'Today' }}
</UCard>
</div>
<div class="relative group">
<div class="absolute -inset-0.5 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-xl opacity-0 group-hover:opacity-100 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-indigo-500/20 transition-all duration-500 hover:-translate-y-1">
<div class="text-center">
<div class="text-3xl font-bold bg-gradient-to-r from-indigo-500 to-purple-500 bg-clip-text text-transparent">
{{ app.stats.android.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
Android
</div>
</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-3xl font-bold text-primary-500">
{{ app.stats.ios.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
iOS
</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-3xl font-bold text-primary-500">
{{ app.stats.android.toLocaleString() }}
</div>
<div class="text-sm text-gray-600 dark:text-gray-400 mt-2">
Android
</div>
</div>
</UCard>
</UCard>
</div>
</div>
<!-- Description -->
<UCard class="mb-8">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
{{ locale === 'zh-CN' ? '应用介绍' : 'Description' }}
</h3>
<p class="text-gray-700 dark:text-gray-300 leading-relaxed">
{{ app.description[locale as 'zh-CN' | 'en-US'] }}
</p>
</UCard>
<div class="relative group mb-8">
<div class="absolute -inset-0.5 bg-gradient-to-r from-primary-500 via-purple-500 to-blue-500 rounded-xl opacity-0 group-hover:opacity-30 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-primary-500/10 transition-all duration-500">
<h3 class="text-xl font-semibold bg-gradient-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 mb-4">
{{ locale === 'zh-CN' ? '应用介绍' : 'Description' }}
</h3>
<p class="text-gray-700 dark:text-gray-300 leading-relaxed">
{{ app.description[locale as 'zh-CN' | 'en-US'] }}
</p>
</UCard>
</div>
<!-- What's New -->
<UCard>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
{{ locale === 'zh-CN' ? '更新内容' : "What's New" }}
</h3>
<ul class="space-y-3">
<li
v-for="(note, index) in app.releaseNotes[locale as 'zh-CN' | 'en-US']"
:key="index"
class="flex items-start gap-3 text-gray-700 dark:text-gray-300"
>
<span class="text-primary-500 mt-1 text-lg"></span>
<span>{{ note }}</span>
</li>
</ul>
</UCard>
<div class="relative group">
<div class="absolute -inset-0.5 bg-gradient-to-r from-purple-500 via-pink-500 to-rose-500 rounded-xl opacity-0 group-hover:opacity-30 blur transition-all duration-500"></div>
<UCard class="relative backdrop-blur-sm bg-white/90 dark:bg-gray-900/90 border border-gray-200/50 dark:border-gray-800/50 hover:shadow-xl hover:shadow-purple-500/10 transition-all duration-500">
<h3 class="text-xl font-semibold bg-gradient-to-r from-gray-900 via-purple-600 to-pink-600 dark:from-white dark:via-purple-400 dark:to-pink-400 bg-clip-text text-transparent mb-4">
{{ locale === 'zh-CN' ? '更新内容' : "What's New" }}
</h3>
<ul class="space-y-3">
<li
v-for="(note, index) in app.releaseNotes[locale as 'zh-CN' | 'en-US']"
:key="index"
class="flex items-start gap-3 text-gray-700 dark:text-gray-300 animate-fade-in-up"
:style="`animation-delay: ${index * 0.1}s`"
>
<span class="text-primary-500 mt-1 text-lg animate-pulse"></span>
<span>{{ note }}</span>
</li>
</ul>
</UCard>
</div>
</div>
</UContainer>
</div>

View File

@@ -84,16 +84,29 @@ useHead({
</script>
<template>
<div class="min-h-screen bg-gray-50 dark:bg-gray-900">
<div class="min-h-screen relative overflow-hidden bg-gradient-to-br from-gray-50 via-blue-50/30 to-purple-50/30 dark:from-gray-950 dark:via-blue-950/20 dark:to-purple-950/20">
<!-- 科技感网格背景 -->
<div class="fixed inset-0 opacity-30 dark:opacity-20 pointer-events-none">
<div class="absolute inset-0" style="background-image: linear-gradient(rgba(99, 102, 241, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(99, 102, 241, 0.1) 1px, transparent 1px); background-size: 50px 50px;"></div>
</div>
<!-- 动态发光球体背景 -->
<div class="fixed inset-0 pointer-events-none overflow-hidden">
<div class="absolute top-1/4 -left-48 w-96 h-96 bg-primary-500/20 rounded-full blur-3xl animate-pulse"></div>
<div class="absolute bottom-1/4 -right-48 w-96 h-96 bg-purple-500/20 rounded-full blur-3xl animate-pulse" style="animation-delay: 1s;"></div>
<div class="absolute top-1/2 left-1/2 w-96 h-96 bg-blue-500/10 rounded-full blur-3xl animate-pulse" style="animation-delay: 2s;"></div>
</div>
<!-- Header -->
<UContainer>
<UContainer class="relative z-10">
<header class="sticky top-0 z-50">
<div class="flex items-center justify-between py-4">
<div class="flex items-center gap-3">
<div class="size-10 rounded-xl bg-linear-to-br from-primary-500 to-primary-600 flex items-center justify-center text-white font-bold text-xl">
R
<div class="flex items-center gap-3 group">
<div class="size-10 rounded-xl bg-gradient-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">
<div class="absolute inset-0 bg-gradient-to-tr from-white/0 via-white/20 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></div>
<span class="relative z-10">R</span>
</div>
<h1 class="text-xl font-bold text-gray-900 dark:text-white">
<h1 class="text-xl font-bold bg-gradient-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">
{{ t('appName') }}
</h1>
</div>
@@ -117,17 +130,18 @@ useHead({
</UContainer>
<!-- Main Content -->
<UContainer class="py-8">
<UContainer class="py-8 relative z-10">
<!-- Search and Filter -->
<div class="mb-8 space-y-4">
<div class="mb-8 space-y-4 animate-fade-in">
<!-- Search -->
<div class="relative max-w-2xl mx-auto">
<div class="relative max-w-2xl mx-auto group">
<div class="absolute -inset-1 bg-gradient-to-r from-primary-500 via-purple-500 to-blue-500 rounded-xl opacity-0 group-hover:opacity-30 blur transition-all duration-500"></div>
<UInput
v-model="searchKeyword"
icon="i-heroicons-magnifying-glass"
size="xl"
:placeholder="locale === 'zh-CN' ? '搜索应用...' : 'Search apps...'"
class="w-full"
class="w-full relative"
/>
</div>
@@ -146,17 +160,28 @@ useHead({
<!-- Apps Grid -->
<div v-if="filteredApps.length > 0" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
<UCard
v-for="app in filteredApps"
<div
v-for="(app, index) in filteredApps"
:key="app.id"
class="cursor-pointer hover:shadow-xl transition-all hover:scale-[1.02]"
@click="openAppDetail(app)"
class="group relative animate-fade-in-up"
:style="`animation-delay: ${index * 0.05}s`"
>
<div class="flex items-start gap-4">
<!-- App Icon -->
<div class="size-16 rounded-2xl bg-linear-to-br from-primary-500 to-primary-600 flex items-center justify-center text-white font-bold text-2xl shrink-0">
{{ app.name.charAt(0) }}
</div>
<!-- 发光边框效果 -->
<div class="absolute -inset-0.5 bg-gradient-to-r from-primary-500 via-purple-500 to-blue-500 rounded-2xl opacity-0 group-hover:opacity-100 blur transition-all duration-500 group-hover:blur-md"></div>
<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 relative overflow-hidden"
@click="openAppDetail(app)"
>
<!-- 内部发光效果 -->
<div class="absolute inset-0 bg-gradient-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="flex items-start gap-4 relative z-10">
<!-- App Icon -->
<div class="size-16 rounded-2xl bg-gradient-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">
<div class="absolute inset-0 bg-gradient-to-tr from-white/0 via-white/30 to-white/0 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-700"></div>
<span class="relative z-10">{{ app.name.charAt(0) }}</span>
</div>
<!-- App Info -->
<div class="flex-1 min-w-0">
@@ -174,34 +199,38 @@ useHead({
</div>
</div>
<!-- Download Buttons -->
<div class="grid grid-cols-3 gap-2 mt-4">
<UButton
v-if="app.downloads.ios"
icon="i-heroicons-device-phone-mobile"
label="iOS"
size="sm"
block
@click.stop="handleDownload(app, 'ios')"
/>
<UButton
v-if="app.downloads.android"
icon="i-heroicons-device-tablet"
label="Android"
size="sm"
block
@click.stop="handleDownload(app, 'android')"
/>
<UButton
v-if="app.downloads.h5"
icon="i-heroicons-globe-alt"
label="Web"
size="sm"
block
@click.stop="handleDownload(app, 'h5')"
/>
</div>
</UCard>
<!-- Download Buttons -->
<div class="grid grid-cols-3 gap-2 mt-4 relative z-10">
<UButton
v-if="app.downloads.ios"
icon="i-heroicons-device-phone-mobile"
label="iOS"
size="sm"
block
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1"
@click.stop="handleDownload(app, 'ios')"
/>
<UButton
v-if="app.downloads.android"
icon="i-heroicons-device-tablet"
label="Android"
size="sm"
block
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1"
@click.stop="handleDownload(app, 'android')"
/>
<UButton
v-if="app.downloads.h5"
icon="i-heroicons-globe-alt"
label="Web"
size="sm"
block
class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1"
@click.stop="handleDownload(app, 'h5')"
/>
</div>
</UCard>
</div>
</div>
<!-- Empty State -->