fb
This commit is contained in:
167
components/Hero.tsx
Normal file
167
components/Hero.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
'use client'
|
||||
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { useState, useEffect } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
|
||||
const heroSlots = [
|
||||
{
|
||||
srcs: [
|
||||
'https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?q=80&w=2070&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1566665797739-1674de7a421a?q=80&w=2070&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?q=80&w=2070&auto=format&fit=crop',
|
||||
],
|
||||
rotate: -12,
|
||||
top: '15%',
|
||||
left: '22%',
|
||||
size: 'w-48 h-64 md:w-64 md:h-80',
|
||||
delay: 0.2
|
||||
},
|
||||
{
|
||||
srcs: [
|
||||
'https://images.unsplash.com/photo-1544124499-58912cbddaad?q=80&w=2127&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?q=80&w=2127&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1571896349842-33c89424de2d?q=80&w=2127&auto=format&fit=crop',
|
||||
],
|
||||
rotate: 10,
|
||||
top: '10%',
|
||||
left: '58%',
|
||||
size: 'w-52 h-64 md:w-72 md:h-80',
|
||||
delay: 0.4
|
||||
},
|
||||
{
|
||||
srcs: [
|
||||
'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=2073&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1519046904884-53103b34b206?q=80&w=2073&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1506929199020-feee17651703?q=80&w=2073&auto=format&fit=crop',
|
||||
],
|
||||
rotate: -8,
|
||||
top: '65%',
|
||||
left: '18%',
|
||||
size: 'w-48 h-60 md:w-64 md:h-72',
|
||||
delay: 0.6
|
||||
},
|
||||
{
|
||||
srcs: [
|
||||
'https://images.unsplash.com/photo-1536935338218-422119932906?q=80&w=1964&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?q=80&w=1964&auto=format&fit=crop',
|
||||
'https://images.unsplash.com/photo-1560185007-cde436f6a4d0?q=80&w=1964&auto=format&fit=crop',
|
||||
],
|
||||
rotate: 15,
|
||||
top: '72%',
|
||||
left: '62%',
|
||||
size: 'w-52 h-64 md:w-72 md:h-88',
|
||||
delay: 0.8
|
||||
}
|
||||
]
|
||||
|
||||
function FloatingSlot({ slot, idx }: { slot: typeof heroSlots[0], idx: number }) {
|
||||
const [currentIdx, setCurrentIdx] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setCurrentIdx((prev) => (prev + 1) % slot.srcs.length)
|
||||
}, 4000 + idx * 500)
|
||||
return () => clearInterval(interval)
|
||||
}, [slot.srcs.length, idx])
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8, rotate: 0, y: 50 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
rotate: slot.rotate,
|
||||
y: 0
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.2,
|
||||
delay: slot.delay,
|
||||
ease: [0.33, 1, 0.68, 1]
|
||||
}}
|
||||
style={{
|
||||
top: slot.top,
|
||||
left: slot.left,
|
||||
zIndex: 5
|
||||
}}
|
||||
className={`absolute ${slot.size} hidden md:block overflow-hidden`}
|
||||
>
|
||||
<AnimatePresence initial={false}>
|
||||
<motion.div
|
||||
key={currentIdx}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 2, ease: "easeInOut" }}
|
||||
className="absolute inset-0"
|
||||
>
|
||||
<Image
|
||||
src={slot.srcs[currentIdx]}
|
||||
alt="Luxury Experience"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 768px) 100vw, 33vw"
|
||||
priority={idx < 2}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Hero({ lang, dict }: { lang: string, dict: any }) {
|
||||
return (
|
||||
<section className="sticky top-0 z-[20] h-screen w-full bg-[#FAF7F0] flex items-center justify-center overflow-hidden">
|
||||
{/* BACKGROUND TEXT */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 1.5, ease: [0.33, 1, 0.68, 1] }}
|
||||
className="relative z-10 w-full text-center px-4"
|
||||
>
|
||||
<h1 className="text-[14vw] leading-[0.8] font-serif tracking-[-0.04em] text-[#1A1A1A] uppercase select-none drop-shadow-sm">
|
||||
{dict.hero.title}
|
||||
</h1>
|
||||
</motion.div>
|
||||
|
||||
{/* FLOATING SLOTS */}
|
||||
{heroSlots.map((slot, idx) => (
|
||||
<FloatingSlot key={idx} slot={slot} idx={idx} />
|
||||
))}
|
||||
|
||||
{/* BOTTOM CONTENT */}
|
||||
<div className="absolute bottom-12 right-12 z-30 max-w-sm text-right flex flex-col items-end space-y-6">
|
||||
<motion.p
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 1.2, duration: 0.8 }}
|
||||
className="text-[#1A1A1A]/70 text-[14px] leading-relaxed font-medium"
|
||||
>
|
||||
{dict.hero.desc}
|
||||
</motion.p>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 1.4, duration: 0.8 }}
|
||||
>
|
||||
<Link
|
||||
href={`/${lang}/suites`}
|
||||
className="inline-block px-8 py-4 bg-[#1A1A1A] text-white text-[12px] font-bold uppercase tracking-widest hover:bg-[#C88C4B] transition-colors duration-300 rounded-[2px] shadow-lg shadow-black/10"
|
||||
>
|
||||
{dict.hero.explore}
|
||||
</Link>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
animate={{ y: [0, 10, 0] }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: "easeInOut" }}
|
||||
className="absolute bottom-8 left-1/2 -translate-x-1/2 opacity-30"
|
||||
>
|
||||
<div className="w-[1px] h-12 bg-[#1A1A1A]" />
|
||||
</motion.div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user