183 lines
8.4 KiB
TypeScript
183 lines
8.4 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { motion, AnimatePresence } from 'motion/react';
|
|
import { SpecialEvent } from '../types';
|
|
|
|
interface SpecialEventsBannerProps {
|
|
specialEvents: SpecialEvent[];
|
|
}
|
|
|
|
const SpecialEventsBanner: React.FC<SpecialEventsBannerProps> = ({ specialEvents }) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const hasEvents = specialEvents && specialEvents.length > 0;
|
|
|
|
const handleRedirect = (link: string) => {
|
|
window.location.href = link;
|
|
};
|
|
|
|
const defaultTitle = "The Grand Chronicles of RIT";
|
|
const defaultDescription = "Hark! The tides have brought forth prestigious gatherings and legendary challenges. Seek thy destiny in the links below.";
|
|
|
|
return (
|
|
<section className="py-12 relative overflow-hidden bg-transparent">
|
|
{/* Background glow (Softer and centered) */}
|
|
<div className="absolute inset-0 z-0 opacity-5 pointer-events-none">
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] h-[400px] bg-amber-500/20 blur-[80px] rounded-full"></div>
|
|
</div>
|
|
|
|
<div className="max-w-2xl mx-auto px-6 relative z-10">
|
|
{/* New Header: Descriptive text above the scroll */}
|
|
<div className="text-center mb-12">
|
|
<h2 className="font-medieval text-3xl md:text-5xl text-[#3e2723] mb-4 opacity-90">
|
|
Special Events Registry
|
|
</h2>
|
|
<p className="font-parchment text-sm md:text-base text-[#5d4037]/70 italic tracking-wide">
|
|
Tap the ancient scroll to reveal the current decrees of RIT
|
|
</p>
|
|
<div className="w-16 h-[1px] bg-[#8d6e63]/20 mx-auto mt-6"></div>
|
|
</div>
|
|
|
|
<motion.div
|
|
initial="closed"
|
|
animate={isOpen ? "open" : "closed"}
|
|
className="relative flex flex-col items-center"
|
|
>
|
|
{/* Top Roller - Interactive */}
|
|
<motion.div
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="relative z-30 w-full h-16 rounded-full shadow-[0_8px_32px_rgba(62,39,35,0.25)] border-[3px] border-[#3e2723]/60 overflow-hidden cursor-pointer active:scale-95 transition-transform"
|
|
style={{
|
|
backgroundImage: 'url(/wood_roller_texture.png)',
|
|
backgroundSize: '100% 100%',
|
|
backgroundPosition: 'center'
|
|
}}
|
|
>
|
|
{/* End Caps: Fixes the 'broken corner' look */}
|
|
<div className="absolute inset-y-0 left-0 w-8 bg-gradient-to-r from-[#1a0f0d] to-transparent opacity-80"></div>
|
|
<div className="absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-[#1a0f0d] to-transparent opacity-80"></div>
|
|
|
|
<div className="absolute inset-0 bg-gradient-to-b from-black/10 via-transparent to-black/20"></div>
|
|
<div className="absolute inset-x-4 inset-y-0 flex items-center justify-between pointer-events-none px-4">
|
|
<div className="w-4 h-4 rounded-full border border-white/5 bg-white/5 blur-[1px]"></div>
|
|
<div className="w-4 h-4 rounded-full border border-white/5 bg-white/5 blur-[1px]"></div>
|
|
</div>
|
|
|
|
<div className="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
|
|
<span className="text-[10px] font-medieval text-white/60 uppercase tracking-[0.3em] bg-black/20 px-4 py-1 rounded-full backdrop-blur-sm">
|
|
{isOpen ? 'Tap to Close' : 'Tap to Open'}
|
|
</span>
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Parchment Body */}
|
|
<motion.div
|
|
variants={{
|
|
closed: {
|
|
height: 0,
|
|
opacity: 0,
|
|
transition: { duration: 0.5, ease: "easeInOut" }
|
|
},
|
|
open: {
|
|
height: 'auto',
|
|
opacity: 1,
|
|
transition: { duration: 0.8, ease: "easeOut" }
|
|
}
|
|
}}
|
|
className="relative z-20 w-[94%] overflow-hidden origin-top"
|
|
style={{
|
|
backgroundImage: 'url(/parchment_texture.png)',
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center'
|
|
}}
|
|
>
|
|
{/* Inner Shadow Shadow */}
|
|
<div className="absolute inset-0 bg-gradient-to-r from-black/5 via-transparent to-black/5 pointer-events-none shadow-inner"></div>
|
|
|
|
<div className="p-8 md:p-12 text-center space-y-8">
|
|
<motion.div
|
|
variants={{
|
|
closed: { opacity: 0, y: -20 },
|
|
open: { opacity: 1, y: 0 }
|
|
}}
|
|
>
|
|
<h2 className="font-medieval text-3xl md:text-5xl text-[#3e2723] mb-4 drop-shadow-sm">
|
|
{hasEvents ? defaultTitle : "The Void Chronicles"}
|
|
</h2>
|
|
<div className="w-24 h-[1px] bg-[#8d6e63]/20 mx-auto mb-6"></div>
|
|
<p className="font-parchment text-base md:text-xl text-[#5d4037] leading-relaxed max-w-lg mx-auto italic opacity-90">
|
|
{hasEvents ? defaultDescription : "The magic portal remains dormant. Check back when the moons align."}
|
|
</p>
|
|
</motion.div>
|
|
|
|
<div className="grid grid-cols-1 gap-6 pt-4">
|
|
{specialEvents.map((event, index) => (
|
|
<motion.div
|
|
key={event.id}
|
|
variants={{
|
|
closed: { opacity: 0, scale: 0.95 },
|
|
open: { opacity: 1, scale: 1 }
|
|
}}
|
|
transition={{ delay: isOpen ? 0.3 + (index * 0.1) : 0 }}
|
|
whileHover={{ scale: 1.02 }}
|
|
className="group cursor-pointer relative"
|
|
onClick={() => handleRedirect(event.link)}
|
|
>
|
|
<div className="border border-[#8d6e63]/15 bg-[#8d6e63]/5 p-5 rounded-lg backdrop-blur-[1px] transition-all duration-300 group-hover:bg-[#8d6e63]/10 group-hover:border-[#8d6e63]/30">
|
|
<h3 className="font-medieval text-xl md:text-2xl text-[#3e2723] mb-2 group-hover:text-[#795548] transition-colors">
|
|
{event.title}
|
|
</h3>
|
|
<p className="font-parchment text-xs md:text-sm text-[#5d4037] line-clamp-2 opacity-80">
|
|
{event.description}
|
|
</p>
|
|
<div className="mt-3 flex justify-end">
|
|
<span className="text-[9px] font-medieval uppercase tracking-[0.2em] text-[#8d6e63] group-hover:text-[#3e2723] flex items-center gap-2">
|
|
Behold <i className="fas fa-feather-pointed"></i>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
|
|
{hasEvents && (
|
|
<div className="font-medieval text-[10px] text-[#8d6e63]/40 uppercase tracking-[0.4em] pt-8">
|
|
End of Scroll
|
|
</div>
|
|
)}
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Bottom Roller - Interactive */}
|
|
<motion.div
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
variants={{
|
|
closed: { y: -64 }, // Perfect overlap (h-16 = 64px)
|
|
open: { y: 0 }
|
|
}}
|
|
transition={{ duration: 0.8, ease: "easeOut" }}
|
|
className="relative z-30 w-full h-16 rounded-full shadow-[0_-8px_32px_rgba(62,39,35,0.25)] border-[3px] border-[#3e2723]/60 overflow-hidden cursor-pointer active:scale-95 transition-transform"
|
|
style={{
|
|
backgroundImage: 'url(/wood_roller_texture.png)',
|
|
backgroundSize: '100% 100%',
|
|
backgroundPosition: 'center'
|
|
}}
|
|
>
|
|
{/* End Caps: Fixes the 'broken corner' look */}
|
|
<div className="absolute inset-y-0 left-0 w-8 bg-gradient-to-r from-[#1a0f0d] to-transparent opacity-80"></div>
|
|
<div className="absolute inset-y-0 right-0 w-8 bg-gradient-to-l from-[#1a0f0d] to-transparent opacity-80"></div>
|
|
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/10 via-transparent to-black/20"></div>
|
|
</motion.div>
|
|
</motion.div>
|
|
</div>
|
|
|
|
<style>{`
|
|
.font-medieval { font-family: 'Pirata One', cursive; }
|
|
.font-parchment { font-family: 'Almendra', serif; }
|
|
`}</style>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default SpecialEventsBanner;
|
|
|