fecbfd1990
refactor: 优化代码健壮性和类型安全 style: 更新字体样式和全局CSS fix: 修复IntersectionObserver潜在空引用问题 chore: 更新依赖和ESLint配置 build: 更新构建ID和路由配置
93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
'use client';
|
|
|
|
import { motion, useReducedMotion } from 'framer-motion';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
interface GradientOrbsProps {
|
|
className?: string;
|
|
count?: number;
|
|
}
|
|
|
|
interface Orb {
|
|
id: number;
|
|
size: number;
|
|
x: number;
|
|
y: number;
|
|
color: string;
|
|
duration: number;
|
|
delay: number;
|
|
}
|
|
|
|
const colorPalette = [
|
|
'rgba(196, 30, 58, 0.15)',
|
|
'rgba(255, 232, 236, 0.2)',
|
|
'rgba(255, 240, 243, 0.18)',
|
|
'rgba(245, 245, 245, 0.15)',
|
|
'rgba(255, 214, 221, 0.2)',
|
|
'rgba(224, 74, 104, 0.12)',
|
|
];
|
|
|
|
export function GradientOrbs({ className = '', count = 5 }: GradientOrbsProps) {
|
|
const prefersReducedMotion = useReducedMotion();
|
|
const [orbs, setOrbs] = useState<Orb[]>([]);
|
|
|
|
useEffect(() => {
|
|
const generatedOrbs: Orb[] = Array.from({ length: count }, (_, i) => ({
|
|
id: i,
|
|
size: Math.random() * 400 + 200,
|
|
x: Math.random() * 100,
|
|
y: Math.random() * 100,
|
|
color: colorPalette[i % colorPalette.length] ?? 'rgba(196, 30, 58, 0.15)',
|
|
duration: Math.random() * 20 + 15,
|
|
delay: Math.random() * 5,
|
|
}));
|
|
setOrbs(generatedOrbs);
|
|
}, [count]);
|
|
|
|
return (
|
|
<div
|
|
className={`absolute inset-0 overflow-hidden ${className}`}
|
|
aria-hidden="true"
|
|
>
|
|
{orbs.map((orb) => (
|
|
<motion.div
|
|
key={orb.id}
|
|
className="absolute rounded-full"
|
|
style={{
|
|
width: orb.size,
|
|
height: orb.size,
|
|
left: `${orb.x}%`,
|
|
top: `${orb.y}%`,
|
|
background: `radial-gradient(circle, ${orb.color} 0%, transparent 70%)`,
|
|
willChange: prefersReducedMotion ? 'auto' : 'transform',
|
|
filter: 'blur(60px)',
|
|
}}
|
|
initial={{
|
|
x: '-50%',
|
|
y: '-50%',
|
|
scale: 1,
|
|
}}
|
|
animate={
|
|
prefersReducedMotion
|
|
? {}
|
|
: {
|
|
x: ['-50%', '-40%', '-60%', '-50%'],
|
|
y: ['-50%', '-60%', '-40%', '-50%'],
|
|
scale: [1, 1.2, 0.9, 1],
|
|
}
|
|
}
|
|
transition={{
|
|
duration: orb.duration,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
delay: orb.delay,
|
|
}}
|
|
/>
|
|
))}
|
|
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-white/20 pointer-events-none" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default GradientOrbs;
|