Files
ayrisapart/components/Hero.tsx
T
ayrisdevandClaude Sonnet 4.6 40b4434a7b feat: i18n fixes, blog rename, footer cleanup, and contact info update
- Rename /news route to /blog across all pages, links, and sitemap
- Fix hardcoded English text in Experiences, QuoteSection, and Footer
  by wiring all content through the TR/EN dictionaries
- Clean up Footer: remove non-existent page links, add contact column
- Update contact info: new phone numbers, bilgi@ email, No:71 address,
  Instagram @ayrisapart link
- Add suppressHydrationWarning to <body> to silence browser-extension
  attribute mismatch errors
- Add sizes prop to all fill-mode Next.js Image components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 18:05:30 +03:00

168 lines
5.3 KiB
TypeScript

'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://res.cloudinary.com/du7xohbct/image/upload/v1776641696/ayrisapart/hero/1_cxfvrw.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641696/ayrisapart/hero/9_vym2pc.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641696/ayrisapart/hero/8_kjih1z.jpg',
],
rotate: 15,
top: '5%',
left: '22%',
size: 'w-48 h-64 md:w-64 md:h-80',
delay: 0.2
},
{
srcs: [
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/7_yuouc0.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/4_eeyoge.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/3_tolqzo.jpg',
],
rotate: -15,
top: '8%',
left: '58%',
size: 'w-52 h-64 md:w-72 md:h-80',
delay: 0.4
},
{
srcs: [
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/2_dfrmwi.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/5_mmcnjw.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641696/ayrisapart/hero/6_x44c4w.jpg',
],
rotate: -8,
top: '60%',
left: '18%',
size: 'w-48 h-60 md:w-64 md:h-72',
delay: 0.6
},
{
srcs: [
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/4_eeyoge.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641695/ayrisapart/hero/5_mmcnjw.jpg',
'https://res.cloudinary.com/du7xohbct/image/upload/v1776641696/ayrisapart/hero/9_vym2pc.jpg',
],
rotate: -8,
top: '62%',
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-30 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-[18vw] leading-[0.8] font-serif tracking-[-0.04em] text-[#1F1C19] 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-36 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>
)
}