112 lines
2.9 KiB
TypeScript
112 lines
2.9 KiB
TypeScript
import React, { useEffect, useRef } from 'react';
|
|
import gsap from 'gsap';
|
|
|
|
interface LoadingScreenProps {
|
|
onComplete: () => void;
|
|
}
|
|
|
|
const LoadingScreen: React.FC<LoadingScreenProps> = ({ onComplete }) => {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const textRef = useRef<HTMLDivElement>(null);
|
|
const progressRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
// Hide scrolling on the body while loading
|
|
document.body.style.overflow = 'hidden';
|
|
|
|
const tl = gsap.timeline({
|
|
onComplete: () => {
|
|
document.body.style.overflow = '';
|
|
onComplete();
|
|
},
|
|
});
|
|
|
|
const chars = textRef.current?.querySelectorAll('.char');
|
|
|
|
// 1. Initial state: progress bar width 0
|
|
gsap.set(progressRef.current, { scaleX: 0, transformOrigin: 'left center' });
|
|
if (chars) {
|
|
gsap.set(chars, { yPercent: 100, opacity: 0 });
|
|
}
|
|
|
|
// 2. Animate the progress bar and reveal text simultaneously
|
|
tl.to(progressRef.current, {
|
|
scaleX: 1,
|
|
duration: 1.5,
|
|
ease: 'power3.inOut',
|
|
})
|
|
.to(
|
|
chars || [],
|
|
{
|
|
yPercent: 0,
|
|
opacity: 1,
|
|
duration: 0.8,
|
|
stagger: 0.05,
|
|
ease: 'power4.out',
|
|
},
|
|
'<0.5' // Start this animation 0.5s into the progress bar loading
|
|
)
|
|
// 3. Keep it visible briefly
|
|
.to({}, { duration: 0.3 })
|
|
// 4. Slide out the individual characters upwards
|
|
.to(
|
|
chars || [],
|
|
{
|
|
yPercent: -100,
|
|
opacity: 0,
|
|
duration: 0.5,
|
|
stagger: 0.02,
|
|
ease: 'power3.in',
|
|
}
|
|
)
|
|
// 5. Fade out progress line
|
|
.to(progressRef.current, { opacity: 0, duration: 0.3 }, '<')
|
|
// 6. Slide the whole curtain up to reveal the homepage
|
|
.to(containerRef.current, {
|
|
yPercent: -100,
|
|
duration: 1,
|
|
ease: 'expo.inOut',
|
|
});
|
|
|
|
return () => {
|
|
tl.kill();
|
|
document.body.style.overflow = '';
|
|
};
|
|
}, [onComplete]);
|
|
|
|
const text = 'BAY AREA IT';
|
|
|
|
return (
|
|
<div
|
|
ref={containerRef}
|
|
className="fixed inset-0 z-[9999] flex flex-col items-center justify-center bg-surface-dark dark:bg-background-dark text-primary"
|
|
>
|
|
<div className="relative overflow-hidden mb-8">
|
|
<h1
|
|
ref={textRef}
|
|
className="font-display text-4xl md:text-6xl font-bold tracking-widest flex overflow-hidden"
|
|
>
|
|
{text.split('').map((char, index) => (
|
|
<span
|
|
key={index}
|
|
className={`char inline-block opacity-0 ${char === ' ' ? 'w-4' : ''}`}
|
|
>
|
|
{char}
|
|
</span>
|
|
))}
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Sleek Minimalist Loading Line */}
|
|
<div className="w-48 md:w-64 h-[2px] bg-white/10 rounded-full overflow-hidden">
|
|
<div
|
|
ref={progressRef}
|
|
className="h-full w-full bg-primary origin-left scale-x-0"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default LoadingScreen;
|