Files
carrotskin/src/app/page.tsx

308 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { motion, useScroll, useTransform } from 'framer-motion';
import {
ArrowRightIcon,
ShieldCheckIcon,
CloudArrowUpIcon,
ShareIcon,
CubeIcon,
UserGroupIcon,
SparklesIcon,
RocketLaunchIcon
} from '@heroicons/react/24/outline';
export default function Home() {
const { scrollYProgress } = useScroll();
const opacity = useTransform(scrollYProgress, [0, 0.3], [1, 0]);
const scale = useTransform(scrollYProgress, [0, 0.3], [1, 0.8]);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [isHovered, setIsHovered] = useState(false);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
setMousePosition({ x: e.clientX, y: e.clientY });
};
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
const features = [
{
icon: ShieldCheckIcon,
title: "Yggdrasil认证",
description: "完整的Minecraft Yggdrasil API支持安全可靠的用户认证系统",
color: "from-amber-400 to-orange-500"
},
{
icon: CloudArrowUpIcon,
title: "云端存储",
description: "无限皮肤存储空间,自动备份,随时随地访问你的皮肤库",
color: "from-orange-400 to-red-500"
},
{
icon: ShareIcon,
title: "社区分享",
description: "与全球玩家分享创作,发现灵感,建立你的粉丝群体",
color: "from-red-400 to-pink-500"
},
{
icon: CubeIcon,
title: "3D预览",
description: "实时3D皮肤预览360度旋转查看支持多种渲染模式",
color: "from-pink-400 to-purple-500"
}
];
const stats = [
{ number: "50K+", label: "注册用户" },
{ number: "200K+", label: "皮肤上传" },
{ number: "1M+", label: "月活用户" },
{ number: "99.9%", label: "服务可用性" }
];
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-orange-50 to-amber-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900">
{/* Animated Background */}
<div className="fixed inset-0 overflow-hidden pointer-events-none">
<div className="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-orange-400/20 to-amber-400/20 rounded-full blur-3xl animate-pulse"></div>
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-gradient-to-tr from-pink-400/20 to-orange-400/20 rounded-full blur-3xl animate-pulse delay-1000"></div>
<div
className="absolute w-32 h-32 bg-gradient-to-r from-orange-400/30 to-amber-400/30 rounded-full blur-2xl transition-all duration-150 ease-out will-change-transform"
style={{
transform: `translate(${mousePosition.x - 64}px, ${mousePosition.y - 64}px) scale(${isHovered ? 1.5 : 1})`
}}
/>
</div>
{/* Hero Section */}
<motion.section
style={{ opacity, scale }}
className="relative min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8 overflow-hidden"
>
<div className="relative z-10 max-w-7xl mx-auto text-center">
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: "easeOut" }}
>
{/* Logo Animation */}
<motion.div
className="mb-8 flex justify-center"
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ duration: 1, type: "spring", stiffness: 100 }}
>
<div className="relative">
<div className="w-24 h-24 bg-gradient-to-br from-orange-400 via-amber-500 to-orange-600 rounded-3xl flex items-center justify-center shadow-2xl">
<span className="text-4xl font-bold text-white">CS</span>
</div>
<motion.div
className="absolute -inset-2 bg-gradient-to-br from-orange-400/30 to-amber-500/30 rounded-3xl blur-lg"
animate={{ scale: [1, 1.1, 1] }}
transition={{ duration: 2, repeat: Infinity }}
/>
</div>
</motion.div>
<h1 className="text-6xl md:text-8xl font-black text-gray-900 dark:text-white mb-6 tracking-tight">
<span className="bg-gradient-to-r from-orange-500 via-amber-500 to-orange-600 bg-clip-text text-transparent">
CarrotSkin
</span>
</h1>
<motion.p
className="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-8 max-w-3xl mx-auto font-light leading-relaxed"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.6 }}
>
<span className="font-semibold text-orange-500">Minecraft Yggdrasil</span>
<br className="hidden sm:block" />
</motion.p>
<motion.div
className="flex flex-col sm:flex-row gap-4 justify-center items-center"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.6 }}
>
<Link
href="/register"
className="group relative overflow-hidden bg-gradient-to-r from-orange-500 to-amber-500 text-white font-semibold py-4 px-8 rounded-2xl transition-all duration-300 hover:shadow-2xl hover:shadow-orange-500/25"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<span className="relative z-10 flex items-center space-x-2">
<span></span>
<ArrowRightIcon className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</span>
<motion.div
className="absolute inset-0 bg-gradient-to-r from-amber-500 to-orange-500"
initial={{ x: '-100%' }}
whileHover={{ x: 0 }}
transition={{ duration: 0.3 }}
/>
</Link>
<Link
href="/skins"
className="group border-2 border-orange-200 dark:border-orange-700 text-orange-600 dark:text-orange-400 font-semibold py-4 px-8 rounded-2xl transition-all duration-300 hover:bg-orange-500 hover:text-white hover:border-orange-500"
>
<span className="flex items-center space-x-2">
<span></span>
<SparklesIcon className="w-5 h-5 group-hover:rotate-12 transition-transform" />
</span>
</Link>
</motion.div>
</motion.div>
</div>
{/* Scroll Indicator */}
<motion.div
className="absolute bottom-12 left-1/2 transform -translate-x-1/2"
animate={{ y: [0, 10, 0] }}
transition={{ duration: 2, repeat: Infinity }}
>
<div className="w-6 h-10 border-2 border-orange-400 rounded-full flex justify-center">
<motion.div
className="w-1 h-3 bg-orange-400 rounded-full mt-2"
animate={{ y: [0, 16, 0] }}
transition={{ duration: 2, repeat: Infinity }}
/>
</div>
</motion.div>
</motion.section>
{/* Stats Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-7xl mx-auto">
<div className="grid grid-cols-2 lg:grid-cols-4 gap-8">
{stats.map((stat, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1, duration: 0.6 }}
viewport={{ once: true }}
className="text-center group"
>
<div className="text-4xl md:text-5xl font-black bg-gradient-to-r from-orange-500 to-amber-500 bg-clip-text text-transparent mb-2">
{stat.number}
</div>
<div className="text-gray-600 dark:text-gray-400 font-medium">
{stat.label}
</div>
<div className="h-1 w-16 bg-gradient-to-r from-orange-400 to-amber-400 mx-auto mt-3 rounded-full group-hover:w-24 transition-all duration-300"></div>
</motion.div>
))}
</div>
</div>
</section>
{/* Features Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8 relative">
<div className="max-w-7xl mx-auto">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
viewport={{ once: true }}
className="text-center mb-16"
>
<h2 className="text-4xl md:text-5xl font-black text-gray-900 dark:text-white mb-6">
<span className="bg-gradient-to-r from-orange-500 to-amber-500 bg-clip-text text-transparent"> </span>
</h2>
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-3xl mx-auto font-light">
</p>
</motion.div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{features.map((feature, index) => (
<motion.div
key={index}
initial={{ opacity: 0, x: index % 2 === 0 ? -50 : 50 }}
whileInView={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1, duration: 0.6 }}
viewport={{ once: true }}
className="group relative"
>
<div className="bg-white/70 dark:bg-gray-800/70 backdrop-blur-lg rounded-3xl p-8 shadow-xl hover:shadow-2xl transition-all duration-300 border border-white/20 dark:border-gray-700/50">
<div className={`w-16 h-16 bg-gradient-to-br ${feature.color} rounded-2xl flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform duration-300`}>
<feature.icon className="w-8 h-8 text-white" />
</div>
<h3 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
{feature.title}
</h3>
<p className="text-gray-600 dark:text-gray-300 leading-relaxed">
{feature.description}
</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* CTA Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-br from-orange-500 via-amber-500 to-orange-600">
<div className="absolute inset-0 bg-black/10"></div>
</div>
<motion.div
className="relative z-10 max-w-4xl mx-auto text-center"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
viewport={{ once: true }}
>
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
className="w-32 h-32 bg-white/10 rounded-full flex items-center justify-center mx-auto mb-8"
>
<RocketLaunchIcon className="w-16 h-16 text-white/80" />
</motion.div>
<h2 className="text-4xl md:text-5xl font-black text-white mb-6">
</h2>
<p className="text-xl text-white/90 mb-8 max-w-2xl mx-auto font-light">
CarrotSkinMinecraft皮肤管理平台
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link
href="/register"
className="group bg-white text-orange-600 hover:bg-gray-100 font-bold py-4 px-8 rounded-2xl transition-all duration-300 inline-flex items-center space-x-2 shadow-2xl"
>
<span></span>
<ArrowRightIcon className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</Link>
<Link
href="/api"
className="border-2 border-white/30 text-white hover:bg-white/10 font-bold py-4 px-8 rounded-2xl transition-all duration-300 inline-flex items-center space-x-2"
>
<span>API文档</span>
<UserGroupIcon className="w-5 h-5" />
</Link>
</div>
</motion.div>
</section>
</div>
);
}