109 lines
4.0 KiB
TypeScript
109 lines
4.0 KiB
TypeScript
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
|
|
interface PortalAnimationProps {
|
|
isVisible: boolean;
|
|
onComplete: () => void;
|
|
targetLink: string;
|
|
}
|
|
|
|
const PortalAnimation: React.FC<PortalAnimationProps> = ({ isVisible, onComplete, targetLink }) => {
|
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
const [statusText, setStatusText] = useState("Initializing Port...");
|
|
|
|
useEffect(() => {
|
|
if (isVisible) {
|
|
// Sequence of status texts for a more high-tech feel
|
|
const statusInterval = setInterval(() => {
|
|
const texts = ["Synchronizing...", "Establishing Link...", "Calibrating Vortex...", "Dimensional Drift...", "Transmitting..."];
|
|
setStatusText(prev => {
|
|
const idx = texts.indexOf(prev);
|
|
return texts[(idx + 1) % texts.length];
|
|
});
|
|
}, 1000);
|
|
|
|
// 5-second delay for the high-quality transition
|
|
const timer = setTimeout(() => {
|
|
// Redirection logic starts - the page will unload
|
|
// The overlay will naturally stay until the browser replaces the page
|
|
window.location.href = targetLink;
|
|
}, 5000);
|
|
|
|
return () => {
|
|
clearTimeout(timer);
|
|
clearInterval(statusInterval);
|
|
};
|
|
}
|
|
}, [isVisible, targetLink]);
|
|
|
|
useEffect(() => {
|
|
if (isVisible && videoRef.current) {
|
|
videoRef.current.play().catch(err => console.error("Video play failed:", err));
|
|
}
|
|
}, [isVisible]);
|
|
|
|
if (!isVisible) return null;
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
// Using Fixed inset-0 and a massive z-index to cover EVERYTHING
|
|
className="fixed inset-0 z-[999999] bg-black flex items-center justify-center overflow-hidden touch-none pointer-events-auto"
|
|
>
|
|
<div className="relative w-full h-full">
|
|
{/* High-Quality Native Video - Absolute Full Screen */}
|
|
<video
|
|
ref={videoRef}
|
|
src="/vortex.mp4"
|
|
muted
|
|
playsInline
|
|
loop
|
|
className="w-full h-full object-cover"
|
|
style={{ width: '100vw', height: '100vh' }}
|
|
/>
|
|
|
|
{/* Premium Overlay Filter */}
|
|
<div className="absolute inset-0 bg-blue-900/20 mix-blend-overlay pointer-events-none"></div>
|
|
|
|
{/* Transition Status Text Overlay */}
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="text-center"
|
|
>
|
|
<div className="mb-4">
|
|
<div className="w-64 h-[2px] bg-white/20 relative overflow-hidden mx-auto">
|
|
<motion.div
|
|
initial={{ x: "-100%" }}
|
|
animate={{ x: "100%" }}
|
|
transition={{ duration: 1.5, repeat: Infinity, ease: "linear" }}
|
|
className="absolute inset-0 bg-orange-500 shadow-[0_0_10px_#f97316]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<span className="text-[10px] font-black uppercase tracking-[0.8em] text-white/70">
|
|
{statusText}
|
|
</span>
|
|
</motion.div>
|
|
</div>
|
|
|
|
{/* Subliminal Transition Glow (Pulses just before redirect) */}
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: [0, 0, 0.6, 0] }}
|
|
transition={{ duration: 5, times: [0, 0.85, 0.95, 1], ease: "easeInOut" }}
|
|
className="absolute inset-0 bg-white pointer-events-none"
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
);
|
|
};
|
|
|
|
export default PortalAnimation;
|