diff --git a/app/page.tsx b/app/page.tsx index 3788d8c..a2d6d85 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -15,7 +15,15 @@ import OperationTimeline from '../src/components/landing/OperationTimeline'; import Footer from '../src/components/shared/Footer'; import FloatingContactButton from '@/src/components/landing/FloatingContactForm'; import LandingChampionshipWorks from '../src/components/landing/HowItWorks'; +import RegistrationEndingPopup from '../src/components/landing/RegistrationEndingPopup'; export default function LandingPage() { + const [showRegPopup, setShowRegPopup] = useState(false); + + useEffect(() => { + const timer = setTimeout(() => setShowRegPopup(true), 3000); + return () => clearTimeout(timer); + }, []); + return (
{/* Blurred Satellite Background */} @@ -72,6 +80,12 @@ export default function LandingPage() { {/* Floating Contact Button */} + + {/* Registration Ending Popup */} + setShowRegPopup(false)} + />
); } \ No newline at end of file diff --git a/src/components/landing/Header.tsx b/src/components/landing/Header.tsx index 02f6740..98f2946 100644 --- a/src/components/landing/Header.tsx +++ b/src/components/landing/Header.tsx @@ -319,8 +319,8 @@ const LandingHeader = () => {
{/* Content Box with Border */} - -

+ +

{

-
+
void; +} + +const RegistrationEndingPopup: React.FC = ({ isOpen, onClose }) => { + const overlayRef = useRef(null); + const modalRef = useRef(null); + const progressBarRef = useRef(null); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + useEffect(() => { + if (isOpen && mounted) { + const tl = gsap.timeline(); + + tl.to(overlayRef.current, { + opacity: 1, + duration: 0.4, + ease: 'power2.out', + }); + + tl.fromTo(modalRef.current, + { scaleY: 0, scaleX: 0.05, opacity: 0 }, + { scaleY: 1, opacity: 1, duration: 0.3, ease: 'power2.inOut' } + ) + .to(modalRef.current, { + scaleX: 1, + duration: 0.3, + ease: 'back.out(1.2)' + }); + + if (progressBarRef.current) { + gsap.fromTo(progressBarRef.current, + { width: '100%' }, + { width: '0%', duration: 25, ease: 'none', delay: 0.6 } + ); + } + + const timer = setTimeout(() => { + handleClose(); + }, 25600); + + return () => { + clearTimeout(timer); + tl.kill(); + }; + } + }, [isOpen, mounted]); + + const handleClose = () => { + const tl = gsap.timeline({ onComplete: onClose }); + tl.to(modalRef.current, { scale: 0.85, opacity: 0, y: 30, duration: 0.3, ease: 'power2.in' }) + .to(overlayRef.current, { opacity: 0, duration: 0.3 }, '<'); + }; + + if (!isOpen || !mounted) return null; + + return createPortal( +
+
+ +
+
+
+ {/* Timer bar */} +
+
+
+ + {/* Close button */} + + + {/* Content */} +
+

+ Registration Ends Soon! +

+ +

+ Last chance to secure your spot and compete in the CTF. +

+ +
+ πŸ“… + Qualifiers: 20th–21st June +
+ + + Sign Up Now πŸš€ + +
+ + {/* Corner brackets */} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
, + document.body + ); +}; + +export default RegistrationEndingPopup; diff --git a/src/components/shared/GlitchText.tsx b/src/components/shared/GlitchText.tsx index 4ba8c98..154a57f 100644 --- a/src/components/shared/GlitchText.tsx +++ b/src/components/shared/GlitchText.tsx @@ -62,28 +62,22 @@ const GlitchText = ({ text, className = "", delay = 0, strikethrough = false, tr }, [started, text, triggerOnView]); return ( - + - {/* Invisible spacer to reserve layout space */} - - - {/* Overlay for the actual effect */} - - {!typingComplete ? ( - - {displayText} - | - - ) : ( - - {text} - - )} - + {!typingComplete ? ( + + {displayText} + | + + ) : ( + + {text} + + )} {/* Strikethrough Lines */} {strikethrough && (