Files
Home/app/page.tsx
T
LufsX 194a2d1810
Vercel Production Deployment / Deploy-Production (push) Failing after 49s
update: design
2025-11-19 11:58:16 +08:00

152 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import Image from "next/image";
import { websites } from "../data/urls";
import Header from "@/components/header";
import Footer from "@/components/footer";
import { motion, useMotionTemplate, useMotionValue, useSpring, useTransform } from "framer-motion";
import { MouseEvent } from "react";
function SpotlightCard({ website, variants }: { website: any; variants: any }) {
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useSpring(useTransform(y, [-0.5, 0.5], ["2.5deg", "-2.5deg"]), { stiffness: 200, damping: 20 });
const rotateY = useSpring(useTransform(x, [-0.5, 0.5], ["-2.5deg", "2.5deg"]), { stiffness: 200, damping: 20 });
function handleMouseMove({ currentTarget, clientX, clientY }: MouseEvent) {
const { left, top, width, height } = currentTarget.getBoundingClientRect();
mouseX.set(clientX - left);
mouseY.set(clientY - top);
x.set((clientX - left) / width - 0.5);
y.set((clientY - top) / height - 0.5);
}
function handleMouseLeave() {
x.set(0);
y.set(0);
}
return (
<motion.div variants={variants} className="h-full" style={{ perspective: 1000 }}>
<motion.a
href={website.link}
rel="noopener noreferrer"
target="_blank"
className="group relative block h-full"
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
rotateX,
rotateY,
transformStyle: "preserve-3d",
}}
whileHover={{ scale: 1.02, y: -5 }}
whileTap={{ scale: 0.98 }}
>
<div className="absolute inset-0 bg-black dark:bg-white rounded-none translate-y-2 translate-x-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
<div className="relative h-full bg-white dark:bg-[#0a0a0a] border border-gray-200 dark:border-gray-800 p-6 rounded-none transition-all duration-300 group-hover:border-black dark:group-hover:border-white overflow-hidden">
<motion.div
className="pointer-events-none absolute -inset-px opacity-0 transition duration-300 group-hover:opacity-100 z-10"
style={{
background: useMotionTemplate`
radial-gradient(
400px circle at ${mouseX}px ${mouseY}px,
rgba(0, 0, 0, 0.08),
transparent 80%
)
`,
}}
/>
<motion.div
className="pointer-events-none absolute -inset-px opacity-0 transition duration-300 group-hover:opacity-100 z-10 hidden dark:block"
style={{
background: useMotionTemplate`
radial-gradient(
400px circle at ${mouseX}px ${mouseY}px,
rgba(255, 255, 255, 0.1),
transparent 80%
)
`,
}}
/>
<div className="relative z-20">
<div className="flex items-start justify-between mb-6">
<div className="p-3 bg-gray-50 dark:bg-white rounded-xl group-hover:bg-gray-100 dark:group-hover:bg-gray-200 transition-all duration-300 shadow-sm border border-gray-100 dark:border-gray-200">
<Image src={website.icon} alt={website.title} width={40} height={40} className="transition-all duration-300" />
</div>
<span className="text-gray-300 dark:text-gray-600 group-hover:text-black dark:group-hover:text-white transition-transform duration-300 group-hover:rotate-45">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="7" y1="17" x2="17" y2="7"></line>
<polyline points="7 7 17 7 17 17"></polyline>
</svg>
</span>
</div>
<h3 className="text-xl font-bold mb-2 text-gray-900 dark:text-white group-hover:underline decoration-2 underline-offset-4">{website.title}</h3>
<p className="text-gray-500 dark:text-gray-400 text-sm leading-relaxed line-clamp-3">{website.description}</p>
</div>
</div>
</motion.a>
</motion.div>
);
}
export default function Home() {
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.08,
delayChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { y: 20, opacity: 0, scale: 0.98, filter: "blur(4px)" },
visible: {
y: 0,
opacity: 1,
scale: 1,
filter: "blur(0px)",
transition: { type: "spring" as const, stiffness: 100, damping: 15, mass: 1 },
},
};
return (
<div className="flex flex-col min-h-screen bg-white dark:bg-black text-black dark:text-white">
<Header />
<motion.main className="w-full max-w-7xl mx-auto px-4 md:px-6 py-16 grow flex flex-col items-center" initial="hidden" animate="visible" variants={containerVariants}>
{/* Hero Section */}
<motion.section className="max-w-4xl w-full mb-24 text-center relative" variants={itemVariants}>
<h2 className="text-5xl md:text-6xl font-black tracking-tighter mb-8 bg-clip-text text-transparent bg-linear-to-b from-gray-900 to-gray-600 dark:from-white dark:to-gray-400">
智能计算实验室
</h2>
<div className="relative inline-block">
<p className="text-xl text-left md:text-2xl leading-relaxed text-gray-600 dark:text-gray-400 font-light max-w-2xl mx-auto">
  在物理的世界里,粒子有形形色色的活法,有的粒子很轻,终生不为人所注意;有的粒子会一鸣惊人,在湮灭时释放出大量的光;有的粒子狡黠善变,一辈子不停地改变身份,时时刻刻要成为别的粒子;但有的粒子一生稳定,怀揣着出发时得到的巨大能量,一生孤独而平静地飞行,只活在自己的轨道里。
</p>
<p className="text-right text-sm text-gray-400 dark:text-gray-500 mt-4 font-mono">—— 李斐然《丁肇中 伟大的是物理》</p>
</div>
</motion.section>
{/* Grid Section */}
<motion.section className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full" variants={containerVariants}>
{websites.map((website, index) => (
<SpotlightCard key={index} website={website} variants={itemVariants} />
))}
</motion.section>
</motion.main>
<Footer />
</div>
);
}