chore: 更新构建ID和相关文件引用
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { RippleButton, SealButton } from '@/components/ui/ripple-button';
|
||||
import { FadeUp, StaggerContainer, StaggerItem, CountUp, FloatingElement, SplitText, GradientText, MagneticButton, BlurReveal, CounterWithEffect } from '@/lib/animations';
|
||||
import { InkDecoration, InkBackground } from '@/components/ui/ink-decoration';
|
||||
import { COMPANY_INFO, STATS } from '@/lib/constants';
|
||||
import { ArrowRight, Shield, Zap, Award } from 'lucide-react';
|
||||
|
||||
@@ -65,84 +66,8 @@ export function HeroSection() {
|
||||
ref={sectionRef}
|
||||
className="relative min-h-screen flex items-center pt-16 overflow-hidden bg-gradient-to-b from-[#FAFAFA] to-white"
|
||||
>
|
||||
<div className="absolute inset-0 pointer-events-none overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 1.2, ease: [0.16, 1, 0.3, 1] }}
|
||||
className="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[600px] bg-[radial-gradient(ellipse_at_center,rgba(28,28,28,0.03)_0%,transparent_60%)]"
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 1.2, delay: 0.2, ease: [0.16, 1, 0.3, 1] }}
|
||||
className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[600px] h-[400px] bg-[radial-gradient(ellipse_at_center,rgba(196,30,58,0.04)_0%,transparent_50%)]"
|
||||
/>
|
||||
|
||||
<FloatingElement amplitude={20} duration={6} className="absolute top-[15%] left-[5%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.5, duration: 0.8 }}
|
||||
className="w-4 h-4 bg-[#C41E3A]/30 rounded-full blur-[1px]"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={25} duration={7} delay={0.3} className="absolute top-[25%] right-[8%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.7, duration: 0.8 }}
|
||||
className="w-6 h-6 bg-[#1C1C1C]/20 rounded-full blur-[1px]"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={18} duration={5} delay={0.6} className="absolute bottom-[30%] left-[10%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.9, duration: 0.8 }}
|
||||
className="w-3 h-3 bg-[#C41E3A]/25 rounded-full"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={22} duration={6.5} delay={0.2} className="absolute bottom-[20%] right-[12%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 1.1, duration: 0.8 }}
|
||||
className="w-5 h-5 bg-[#1C1C1C]/15 rounded-full blur-[1px]"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={15} duration={5.5} delay={0.8} className="absolute top-[40%] left-[15%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 1.3, duration: 0.8 }}
|
||||
className="w-2 h-2 bg-[#C41E3A]/40 rounded-full"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={30} duration={8} delay={0.4} className="absolute top-[60%] right-[5%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 1.5, duration: 0.8 }}
|
||||
className="w-8 h-8 border-2 border-[#C41E3A]/20 rounded-full"
|
||||
/>
|
||||
</FloatingElement>
|
||||
|
||||
<FloatingElement amplitude={12} duration={4.5} delay={1} className="absolute top-[35%] right-[20%]">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 1.7, duration: 0.8 }}
|
||||
className="w-2 h-2 bg-[#1C1C1C]/30 rounded-full"
|
||||
/>
|
||||
</FloatingElement>
|
||||
</div>
|
||||
<InkBackground />
|
||||
<InkDecoration variant="balanced" />
|
||||
|
||||
<div className="container-wide py-24 md:py-32 lg:py-40 relative z-10">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
|
||||
@@ -0,0 +1,553 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { useMemo, useState, useEffect } from 'react';
|
||||
|
||||
interface InkDropProps {
|
||||
size?: number;
|
||||
opacity?: number;
|
||||
color?: string;
|
||||
blur?: number;
|
||||
delay?: number;
|
||||
duration?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InkDrop({
|
||||
size = 20,
|
||||
opacity = 0.15,
|
||||
color = '#1C1C1C',
|
||||
blur = 0,
|
||||
delay = 0,
|
||||
duration = 8,
|
||||
className = ''
|
||||
}: InkDropProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={`absolute rounded-full ${className}`}
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
backgroundColor: color,
|
||||
opacity,
|
||||
filter: blur > 0 ? `blur(${blur}px)` : 'none',
|
||||
}}
|
||||
initial={{ scale: 0, opacity: 0 }}
|
||||
animate={{
|
||||
scale: [0.8, 1.2, 1],
|
||||
opacity: [0, opacity, opacity],
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.5,
|
||||
delay,
|
||||
ease: [0.16, 1, 0.3, 1],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface InkSplashProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InkSplash({
|
||||
size = 60,
|
||||
color = '#C41E3A',
|
||||
opacity = 0.2,
|
||||
delay = 0,
|
||||
className = ''
|
||||
}: InkSplashProps) {
|
||||
return (
|
||||
<motion.svg
|
||||
viewBox="0 0 100 100"
|
||||
width={size}
|
||||
height={size}
|
||||
className={`absolute ${className}`}
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity, scale: 1 }}
|
||||
transition={{ duration: 1.2, delay, ease: [0.16, 1, 0.3, 1] }}
|
||||
>
|
||||
<motion.path
|
||||
d="M50 10 Q30 25 35 50 Q30 75 50 90 Q70 75 65 50 Q70 25 50 10"
|
||||
fill={color}
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
animate={{ pathLength: 1, opacity: 1 }}
|
||||
transition={{ duration: 2, delay: delay + 0.3, ease: [0.16, 1, 0.3, 1] }}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
}
|
||||
|
||||
interface SealStampProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function SealStamp({
|
||||
size = 40,
|
||||
color = '#C41E3A',
|
||||
opacity = 0.15,
|
||||
delay = 0,
|
||||
className = ''
|
||||
}: SealStampProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={`absolute ${className}`}
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
border: `2px solid ${color}`,
|
||||
borderRadius: '4px',
|
||||
opacity: 0,
|
||||
transform: 'rotate(-8deg)',
|
||||
}}
|
||||
initial={{ opacity: 0, scale: 1.5, rotate: -20 }}
|
||||
animate={{ opacity, scale: 1, rotate: -8 }}
|
||||
transition={{
|
||||
type: 'spring',
|
||||
stiffness: 200,
|
||||
damping: 15,
|
||||
delay,
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="absolute inset-1 border border-current"
|
||||
style={{ borderColor: color, opacity: 0.5 }}
|
||||
initial={{ scale: 0.8 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ duration: 0.5, delay: delay + 0.3 }}
|
||||
/>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
interface InkStainProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
blur?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InkStain({
|
||||
size = 100,
|
||||
color = '#1C1C1C',
|
||||
opacity = 0.05,
|
||||
blur = 20,
|
||||
delay = 0,
|
||||
className = ''
|
||||
}: InkStainProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={`absolute ${className}`}
|
||||
style={{
|
||||
width: size,
|
||||
height: size * 0.8,
|
||||
backgroundColor: color,
|
||||
borderRadius: '50% 40% 60% 45%',
|
||||
opacity: 0,
|
||||
filter: `blur(${blur}px)`,
|
||||
}}
|
||||
initial={{ opacity: 0, scale: 0.5 }}
|
||||
animate={{ opacity, scale: 1 }}
|
||||
transition={{ duration: 2, delay, ease: [0.16, 1, 0.3, 1] }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface InkLineProps {
|
||||
width?: number;
|
||||
height?: number;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InkLine({
|
||||
width = 200,
|
||||
height = 2,
|
||||
color = '#1C1C1C',
|
||||
opacity = 0.1,
|
||||
delay = 0,
|
||||
className = ''
|
||||
}: InkLineProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className={`absolute ${className}`}
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
backgroundColor: color,
|
||||
opacity: 0,
|
||||
borderRadius: height / 2,
|
||||
}}
|
||||
initial={{ opacity: 0, scaleX: 0 }}
|
||||
animate={{ opacity, scaleX: 1 }}
|
||||
transition={{ duration: 1.5, delay, ease: [0.16, 1, 0.3, 1] }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
interface BrushStrokeProps {
|
||||
width?: number;
|
||||
height?: number;
|
||||
color?: string;
|
||||
opacity?: number;
|
||||
delay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function BrushStroke({
|
||||
width = 150,
|
||||
height = 30,
|
||||
color = '#C41E3A',
|
||||
opacity = 0.12,
|
||||
delay = 0,
|
||||
className = ''
|
||||
}: BrushStrokeProps) {
|
||||
return (
|
||||
<motion.svg
|
||||
viewBox="0 0 150 30"
|
||||
width={width}
|
||||
height={height}
|
||||
className={`absolute ${className}`}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity }}
|
||||
transition={{ duration: 1, delay }}
|
||||
>
|
||||
<motion.path
|
||||
d="M0 15 Q20 5 40 15 Q60 25 80 15 Q100 5 120 15 Q135 20 150 15"
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 1 }}
|
||||
transition={{ duration: 2, delay: delay + 0.5, ease: [0.16, 1, 0.3, 1] }}
|
||||
/>
|
||||
</motion.svg>
|
||||
);
|
||||
}
|
||||
|
||||
interface FloatingInkProps {
|
||||
count?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function FloatingInk({ count = 15, className = '' }: FloatingInkProps) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
const elements = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
const items = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const type = i % 5;
|
||||
const baseDelay = i * 0.15;
|
||||
|
||||
items.push({
|
||||
id: i,
|
||||
type,
|
||||
delay: baseDelay,
|
||||
props: {
|
||||
left: `${10 + Math.random() * 80}%`,
|
||||
top: `${10 + Math.random() * 80}%`,
|
||||
},
|
||||
animX: Math.random() * 10 - 5,
|
||||
animDuration: 6 + Math.random() * 4,
|
||||
size: type === 0 ? 8 + Math.random() * 16 :
|
||||
type === 1 ? 4 + Math.random() * 8 :
|
||||
type === 2 ? 20 + Math.random() * 30 :
|
||||
type === 3 ? 60 + Math.random() * 80 : 80 + Math.random() * 100,
|
||||
opacity: type === 0 ? 0.08 + Math.random() * 0.1 :
|
||||
type === 1 ? 0.1 + Math.random() * 0.15 :
|
||||
type === 2 ? 0.08 + Math.random() * 0.08 :
|
||||
type === 3 ? 0.03 + Math.random() * 0.04 : 0.06 + Math.random() * 0.08,
|
||||
blur: type === 0 ? Math.random() * 2 : 0,
|
||||
height: type === 4 ? 15 + Math.random() * 20 : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
}, [count, isMounted]);
|
||||
|
||||
return (
|
||||
<div className={`absolute inset-0 pointer-events-none overflow-hidden ${className}`}>
|
||||
{elements.map((el) => (
|
||||
<motion.div
|
||||
key={el.id}
|
||||
className="absolute"
|
||||
style={el.props}
|
||||
animate={{
|
||||
y: [0, -20, 0],
|
||||
x: [0, el.animX, 0],
|
||||
}}
|
||||
transition={{
|
||||
duration: el.animDuration,
|
||||
delay: el.delay,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
{el.type === 0 && (
|
||||
<InkDrop
|
||||
size={el.size}
|
||||
opacity={el.opacity}
|
||||
blur={el.blur}
|
||||
delay={el.delay}
|
||||
/>
|
||||
)}
|
||||
{el.type === 1 && (
|
||||
<InkDrop
|
||||
size={el.size}
|
||||
opacity={el.opacity}
|
||||
color="#C41E3A"
|
||||
delay={el.delay}
|
||||
/>
|
||||
)}
|
||||
{el.type === 2 && (
|
||||
<SealStamp
|
||||
size={el.size}
|
||||
opacity={el.opacity}
|
||||
delay={el.delay}
|
||||
/>
|
||||
)}
|
||||
{el.type === 3 && (
|
||||
<InkStain
|
||||
size={el.size}
|
||||
opacity={el.opacity}
|
||||
delay={el.delay}
|
||||
/>
|
||||
)}
|
||||
{el.type === 4 && (
|
||||
<BrushStroke
|
||||
width={el.size}
|
||||
height={el.height}
|
||||
opacity={el.opacity}
|
||||
delay={el.delay}
|
||||
/>
|
||||
)}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface InkDecorationProps {
|
||||
variant?: 'minimal' | 'balanced' | 'rich';
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function InkDecoration({ variant = 'balanced', className = '' }: InkDecorationProps) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
const config = {
|
||||
minimal: { drops: 3, splashes: 1, seals: 1, stains: 1, strokes: 1 },
|
||||
balanced: { drops: 5, splashes: 2, seals: 2, stains: 2, strokes: 2 },
|
||||
rich: { drops: 8, splashes: 3, seals: 3, stains: 3, strokes: 3 },
|
||||
};
|
||||
|
||||
const { drops, splashes, seals, stains, strokes } = config[variant];
|
||||
|
||||
const dropPositions = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
return Array.from({ length: drops }, (_, i) => ({
|
||||
left: `${15 + (i * 70 / drops)}%`,
|
||||
top: `${20 + Math.random() * 60}%`,
|
||||
size: 6 + Math.random() * 14,
|
||||
opacity: 0.06 + Math.random() * 0.1,
|
||||
blur: Math.random() * 3,
|
||||
isRed: i % 3 === 0,
|
||||
}));
|
||||
}, [drops, isMounted]);
|
||||
|
||||
const splashPositions = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
return Array.from({ length: splashes }, (_, i) => ({
|
||||
left: `${20 + (i * 60 / splashes)}%`,
|
||||
top: `${15 + Math.random() * 70}%`,
|
||||
size: 40 + Math.random() * 40,
|
||||
}));
|
||||
}, [splashes, isMounted]);
|
||||
|
||||
const sealPositions = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
return Array.from({ length: seals }, (_, i) => ({
|
||||
left: `${25 + (i * 50 / seals)}%`,
|
||||
top: `${25 + Math.random() * 50}%`,
|
||||
size: 25 + Math.random() * 25,
|
||||
}));
|
||||
}, [seals, isMounted]);
|
||||
|
||||
const stainPositions = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
return Array.from({ length: stains }, (_, i) => ({
|
||||
left: `${10 + (i * 80 / stains)}%`,
|
||||
top: `${30 + Math.random() * 40}%`,
|
||||
size: 80 + Math.random() * 60,
|
||||
}));
|
||||
}, [stains, isMounted]);
|
||||
|
||||
const strokePositions = useMemo(() => {
|
||||
if (!isMounted) return [];
|
||||
return Array.from({ length: strokes }, (_, i) => ({
|
||||
left: `${15 + (i * 70 / strokes)}%`,
|
||||
top: `${40 + Math.random() * 30}%`,
|
||||
width: 100 + Math.random() * 100,
|
||||
}));
|
||||
}, [strokes, isMounted]);
|
||||
|
||||
return (
|
||||
<div className={`absolute inset-0 pointer-events-none overflow-hidden ${className}`}>
|
||||
{dropPositions.map((pos, i) => (
|
||||
<motion.div
|
||||
key={`drop-${i}`}
|
||||
className="absolute"
|
||||
style={{ left: pos.left, top: pos.top }}
|
||||
animate={{
|
||||
y: [0, -15, 0],
|
||||
scale: [1, 1.1, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 5 + Math.random() * 3,
|
||||
delay: i * 0.2,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<InkDrop
|
||||
size={pos.size}
|
||||
opacity={pos.opacity}
|
||||
blur={pos.blur}
|
||||
color={pos.isRed ? '#C41E3A' : '#1C1C1C'}
|
||||
delay={i * 0.1}
|
||||
/>
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
{splashPositions.map((pos, i) => (
|
||||
<motion.div
|
||||
key={`splash-${i}`}
|
||||
className="absolute"
|
||||
style={{ left: pos.left, top: pos.top }}
|
||||
animate={{
|
||||
y: [0, -10, 0],
|
||||
rotate: [0, 5, -5, 0],
|
||||
}}
|
||||
transition={{
|
||||
duration: 7 + Math.random() * 3,
|
||||
delay: i * 0.3,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<InkSplash size={pos.size} opacity={0.12} delay={i * 0.15} />
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
{sealPositions.map((pos, i) => (
|
||||
<motion.div
|
||||
key={`seal-${i}`}
|
||||
className="absolute"
|
||||
style={{ left: pos.left, top: pos.top }}
|
||||
animate={{
|
||||
y: [0, -8, 0],
|
||||
rotate: [-8, -5, -10, -8],
|
||||
}}
|
||||
transition={{
|
||||
duration: 6 + Math.random() * 2,
|
||||
delay: i * 0.25,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<SealStamp size={pos.size} opacity={0.1} delay={i * 0.2} />
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
{stainPositions.map((pos, i) => (
|
||||
<motion.div
|
||||
key={`stain-${i}`}
|
||||
className="absolute"
|
||||
style={{ left: pos.left, top: pos.top }}
|
||||
animate={{
|
||||
scale: [1, 1.05, 1],
|
||||
opacity: [0.04, 0.06, 0.04],
|
||||
}}
|
||||
transition={{
|
||||
duration: 8 + Math.random() * 4,
|
||||
delay: i * 0.35,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<InkStain size={pos.size} opacity={0.05} delay={i * 0.1} />
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
{strokePositions.map((pos, i) => (
|
||||
<motion.div
|
||||
key={`stroke-${i}`}
|
||||
className="absolute"
|
||||
style={{ left: pos.left, top: pos.top }}
|
||||
animate={{
|
||||
x: [0, 10, 0],
|
||||
opacity: [0.08, 0.12, 0.08],
|
||||
}}
|
||||
transition={{
|
||||
duration: 6 + Math.random() * 3,
|
||||
delay: i * 0.3,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<BrushStroke width={pos.width} opacity={0.1} delay={i * 0.15} />
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function InkBackground() {
|
||||
return (
|
||||
<div className="absolute inset-0 pointer-events-none overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 2 }}
|
||||
className="absolute top-0 left-1/4 w-[500px] h-[500px] bg-[radial-gradient(ellipse_at_center,rgba(28,28,28,0.02)_0%,transparent_70%)]"
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 2, delay: 0.3 }}
|
||||
className="absolute bottom-0 right-1/4 w-[400px] h-[400px] bg-[radial-gradient(ellipse_at_center,rgba(196,30,58,0.03)_0%,transparent_60%)]"
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 2, delay: 0.6 }}
|
||||
className="absolute top-1/3 right-0 w-[300px] h-[300px] bg-[radial-gradient(ellipse_at_center,rgba(28,28,28,0.015)_0%,transparent_50%)]"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user