fecbfd1990
refactor: 优化代码健壮性和类型安全 style: 更新字体样式和全局CSS fix: 修复IntersectionObserver潜在空引用问题 chore: 更新依赖和ESLint配置 build: 更新构建ID和路由配置
136 lines
4.4 KiB
TypeScript
136 lines
4.4 KiB
TypeScript
'use client';
|
|
|
|
import { motion, useReducedMotion } from 'framer-motion';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
interface InkTechFusionProps {
|
|
className?: string;
|
|
variant?: 'subtle' | 'prominent' | 'dynamic';
|
|
primaryColor?: string;
|
|
secondaryColor?: string;
|
|
}
|
|
|
|
interface InkBlob {
|
|
id: number;
|
|
x: number;
|
|
y: number;
|
|
size: number;
|
|
opacity: number;
|
|
duration: number;
|
|
delay: number;
|
|
color: string;
|
|
}
|
|
|
|
export function InkTechFusion({
|
|
className = '',
|
|
variant = 'subtle',
|
|
primaryColor = '#C41E3A',
|
|
secondaryColor = '#1C1C1C',
|
|
}: InkTechFusionProps) {
|
|
const prefersReducedMotion = useReducedMotion();
|
|
const [blobs, setBlobs] = useState<InkBlob[]>([]);
|
|
|
|
useEffect(() => {
|
|
const count = variant === 'prominent' ? 8 : variant === 'dynamic' ? 12 : 5;
|
|
const generated: InkBlob[] = Array.from({ length: count }, (_, i) => ({
|
|
id: i,
|
|
x: Math.random() * 100,
|
|
y: Math.random() * 100,
|
|
size: Math.random() * 300 + 100,
|
|
opacity: Math.random() * 0.06 + 0.02,
|
|
duration: Math.random() * 25 + 20,
|
|
delay: Math.random() * 5,
|
|
color: i % 2 === 0 ? primaryColor : secondaryColor,
|
|
}));
|
|
setBlobs(generated);
|
|
}, [variant, primaryColor, secondaryColor]);
|
|
|
|
return (
|
|
<div className={`absolute inset-0 overflow-hidden ${className}`} aria-hidden="true">
|
|
{blobs.map((blob) => (
|
|
<motion.div
|
|
key={blob.id}
|
|
className="absolute"
|
|
style={{
|
|
left: `${blob.x}%`,
|
|
top: `${blob.y}%`,
|
|
width: blob.size,
|
|
height: blob.size,
|
|
background: `radial-gradient(circle, ${blob.color}${Math.round(blob.opacity * 255).toString(16).padStart(2, '0')} 0%, transparent 70%)`,
|
|
borderRadius: '50%',
|
|
filter: 'blur(40px)',
|
|
willChange: prefersReducedMotion ? 'auto' : 'transform',
|
|
}}
|
|
initial={{ scale: 0.8, opacity: 0 }}
|
|
animate={
|
|
prefersReducedMotion
|
|
? { scale: 1, opacity: blob.opacity }
|
|
: {
|
|
scale: [0.8, 1.2, 0.9, 1.1, 0.8],
|
|
opacity: [0, blob.opacity, blob.opacity * 1.2, blob.opacity, 0],
|
|
x: [0, 30, -20, 10, 0],
|
|
y: [0, -20, 30, -10, 0],
|
|
}
|
|
}
|
|
transition={{
|
|
duration: blob.duration,
|
|
repeat: Infinity,
|
|
ease: 'easeInOut',
|
|
delay: blob.delay,
|
|
}}
|
|
/>
|
|
))}
|
|
|
|
<svg className="absolute inset-0 w-full h-full opacity-10">
|
|
<defs>
|
|
<filter id="ink-blur">
|
|
<feGaussianBlur in="SourceGraphic" stdDeviation="3" />
|
|
</filter>
|
|
<pattern id="ink-texture" width="100" height="100" patternUnits="userSpaceOnUse">
|
|
<circle cx="50" cy="50" r="1" fill={primaryColor} opacity="0.2" />
|
|
<circle cx="25" cy="75" r="0.5" fill={secondaryColor} opacity="0.15" />
|
|
<circle cx="75" cy="25" r="0.8" fill={primaryColor} opacity="0.18" />
|
|
</pattern>
|
|
</defs>
|
|
<rect width="100%" height="100%" fill="url(#ink-texture)" filter="url(#ink-blur)" />
|
|
</svg>
|
|
|
|
<svg className="absolute inset-0 w-full h-full opacity-5">
|
|
<defs>
|
|
<linearGradient id="tech-line-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" stopColor={primaryColor} stopOpacity="0" />
|
|
<stop offset="50%" stopColor={primaryColor} stopOpacity="0.3" />
|
|
<stop offset="100%" stopColor={primaryColor} stopOpacity="0" />
|
|
</linearGradient>
|
|
</defs>
|
|
<motion.line
|
|
x1="0%"
|
|
y1="30%"
|
|
x2="100%"
|
|
y2="70%"
|
|
stroke="url(#tech-line-gradient)"
|
|
strokeWidth="1"
|
|
initial={{ pathLength: 0 }}
|
|
animate={prefersReducedMotion ? { pathLength: 1 } : { pathLength: [0, 1, 1, 0] }}
|
|
transition={{ duration: 15, repeat: Infinity, ease: 'easeInOut' }}
|
|
/>
|
|
<motion.line
|
|
x1="0%"
|
|
y1="70%"
|
|
x2="100%"
|
|
y2="30%"
|
|
stroke="url(#tech-line-gradient)"
|
|
strokeWidth="1"
|
|
initial={{ pathLength: 0 }}
|
|
animate={prefersReducedMotion ? { pathLength: 1 } : { pathLength: [0, 1, 1, 0] }}
|
|
transition={{ duration: 18, repeat: Infinity, ease: 'easeInOut', delay: 3 }}
|
|
/>
|
|
</svg>
|
|
|
|
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-white/50" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default InkTechFusion;
|