feat: 添加预览效果页面并优化交互效果
refactor: 优化代码健壮性和类型安全 style: 更新字体样式和全局CSS fix: 修复IntersectionObserver潜在空引用问题 chore: 更新依赖和ESLint配置 build: 更新构建ID和路由配置
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
'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;
|
||||
Reference in New Issue
Block a user