diff --git a/packages/distribute/assets/css/animations.css b/packages/distribute/assets/css/animations.css index d76b8fe..a36388f 100644 --- a/packages/distribute/assets/css/animations.css +++ b/packages/distribute/assets/css/animations.css @@ -235,3 +235,182 @@ scroll-behavior: smooth; -webkit-overflow-scrolling: touch; } + +/* 涟漪扩散动画 */ +@keyframes ripple-expand { + 0% { + transform: translate(-50%, -50%) scale(0); + opacity: 1; + } + 100% { + transform: translate(-50%, -50%) scale(40); + opacity: 0; + } +} + +/* 微妙的悬浮动画 */ +@keyframes float-subtle { + 0%, 100% { + transform: translateY(0) translateZ(0); + } + 50% { + transform: translateY(-5px) translateZ(10px); + } +} + +.animate-float-subtle { + animation: float-subtle 3s ease-in-out infinite; +} + +/* 脉冲光环动画 */ +@keyframes pulse-ring { + 0% { + transform: scale(0.95); + opacity: 1; + } + 50% { + transform: scale(1.05); + opacity: 0.8; + } + 100% { + transform: scale(0.95); + opacity: 1; + } +} + +.animate-pulse-ring { + animation: pulse-ring 2s ease-in-out infinite; +} + +/* 发光脉冲动画 */ +@keyframes pulse-glow { + 0%, 100% { + opacity: 0.5; + } + 50% { + opacity: 1; + } +} + +.animate-pulse-glow { + animation: pulse-glow 1.5s ease-in-out infinite; +} + +/* 微妙的脉冲动画 */ +@keyframes pulse-subtle { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.8; + } +} + +.animate-pulse-subtle { + animation: pulse-subtle 2s ease-in-out infinite; +} + +/* 微妙的滑入动画 */ +@keyframes slide-in-subtle { + from { + opacity: 0; + transform: translateX(10px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-slide-in-subtle { + animation: slide-in-subtle 0.5s ease-out; +} + +/* 3D透视 */ +.perspective-1000 { + perspective: 1000px; +} + +.transform-style-3d { + transform-style: preserve-3d; +} + +.transform-gpu { + transform: translateZ(0); + backface-visibility: hidden; + will-change: transform; +} + +/* 3D旋转效果 */ +.hover\:rotate-y-2:hover { + transform: translateY(-0.5rem) rotateY(2deg) translateZ(20px); +} + +/* 按钮闪光效果 */ +@keyframes button-shine { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} + +.animate-button-shine { + animation: button-shine 2s ease-in-out infinite; +} + +/* 震动效果 */ +@keyframes shake { + 0%, 100% { + transform: translateX(0); + } + 25% { + transform: translateX(-5px); + } + 75% { + transform: translateX(5px); + } +} + +.animate-shake { + animation: shake 0.5s ease-in-out; +} + +/* 弹跳效果 */ +@keyframes bounce-in { + 0% { + opacity: 0; + transform: scale(0.3) translateY(50px); + } + 50% { + transform: scale(1.05) translateY(-10px); + } + 70% { + transform: scale(0.9) translateY(0); + } + 100% { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +.animate-bounce-in { + animation: bounce-in 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); +} + +/* 呼吸灯效果 */ +@keyframes breathe { + 0%, 100% { + opacity: 0.6; + transform: scale(1); + } + 50% { + opacity: 1; + transform: scale(1.1); + } +} + +.animate-breathe { + animation: breathe 2s ease-in-out infinite; +} diff --git a/packages/distribute/pages/index.vue b/packages/distribute/pages/index.vue index 799a390..9cc5eea 100644 --- a/packages/distribute/pages/index.vue +++ b/packages/distribute/pages/index.vue @@ -46,8 +46,42 @@ function openAppDetail(app: AppInfo) { navigateTo(`/apps/${app.id}`) } +// 创建涟漪效果 +function createRipple(event: MouseEvent | TouchEvent) { + const button = event.currentTarget as HTMLElement + const ripple = document.createElement('span') + const rect = button.getBoundingClientRect() + + const x = ('touches' in event ? event.touches[0]!.clientX : event.clientX) - rect.left + const y = ('touches' in event ? event.touches[0]!.clientY : event.clientY) - rect.top + + ripple.style.cssText = ` + position: absolute; + left: ${x}px; + top: ${y}px; + width: 10px; + height: 10px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.6); + transform: translate(-50%, -50%) scale(0); + animation: ripple-expand 0.6s ease-out; + pointer-events: none; + z-index: 100; + ` + + button.style.position = 'relative' + button.style.overflow = 'hidden' + button.appendChild(ripple) + + setTimeout(() => ripple.remove(), 600) +} + // 下载处理 -async function handleDownload(app: AppInfo, type: 'ios' | 'android' | 'h5') { +async function handleDownload(app: AppInfo, type: 'ios' | 'android' | 'h5', event?: MouseEvent | TouchEvent) { + if (event) { + createRipple(event) + } + const url = app.downloads[type] if (!url) { @@ -87,14 +121,17 @@ useHead({
-
+
-
-
-
+
+
+
+ +
+
@@ -102,11 +139,12 @@ useHead({
-
+
- R +
+ R
-

+

{{ t('appName') }}

@@ -162,18 +200,21 @@ useHead({
-
+
-
+
+ + +
@@ -181,23 +222,26 @@ useHead({
-
+
+
- + +
+
-
-

+
+

{{ app.name }}

-

+

{{ app.shortDescription[locale as 'zh-CN' | 'en-US'] }}

-
- v{{ app.version }} +
+ v{{ app.version }} - {{ app.stats.total.toLocaleString() }} {{ locale === 'zh-CN' ? '次下载' : 'downloads' }} + {{ app.stats.total.toLocaleString() }} {{ locale === 'zh-CN' ? '次下载' : 'downloads' }}
@@ -210,27 +254,33 @@ useHead({ label="iOS" size="sm" block - class="transition-all duration-300 hover:shadow-lg hover:shadow-blue-500/50 hover:-translate-y-1 active:scale-95 active:shadow-md touch-manipulation" - @click.stop="handleDownload(app, 'ios')" - /> + 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" + @click.stop="(e) => handleDownload(app, 'ios', e)" + > + + + 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" + @click.stop="(e) => handleDownload(app, 'android', e)" + > + + + 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" + @click.stop="(e) => handleDownload(app, 'h5', e)" + > + +