105 lines
3.5 KiB
TypeScript
105 lines
3.5 KiB
TypeScript
'use client'
|
||
|
||
import { useRef } from 'react'
|
||
import { useTranslations } from 'next-intl'
|
||
import { motion, useInView } from 'framer-motion'
|
||
import Image from 'next/image'
|
||
import { TreePine, Users, Dumbbell, Wind } from 'lucide-react'
|
||
|
||
const amenities = [
|
||
{
|
||
key: 'livingAreas' as const,
|
||
descKey: 'livingDesc' as const,
|
||
icon: Users,
|
||
image: 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800&q=80',
|
||
},
|
||
{
|
||
key: 'playground' as const,
|
||
descKey: 'playgroundDesc' as const,
|
||
icon: Wind,
|
||
image: 'https://images.unsplash.com/photo-1575783970733-1aaedde1db74?w=800&q=80',
|
||
},
|
||
{
|
||
key: 'sports' as const,
|
||
descKey: 'sportsDesc' as const,
|
||
icon: Dumbbell,
|
||
image: 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=800&q=80',
|
||
},
|
||
{
|
||
key: 'forest' as const,
|
||
descKey: 'forestDesc' as const,
|
||
icon: TreePine,
|
||
image: 'https://images.unsplash.com/photo-1448375240586-882707db888b?w=800&q=80',
|
||
},
|
||
]
|
||
|
||
export default function AmenitiesSection() {
|
||
const t = useTranslations('amenities')
|
||
const ref = useRef<HTMLDivElement>(null)
|
||
const isInView = useInView(ref, { once: true, margin: '-80px' })
|
||
|
||
return (
|
||
<section className="bg-vesta-cream py-24 md:py-32">
|
||
<div ref={ref} className="container mx-auto px-6">
|
||
{/* Başlık */}
|
||
<div className="text-center mb-16">
|
||
<motion.p
|
||
initial={{ opacity: 0, y: 15 }}
|
||
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
||
transition={{ duration: 0.5 }}
|
||
className="text-vesta-earth text-xs tracking-[0.3em] uppercase mb-3"
|
||
>
|
||
{t('label')}
|
||
</motion.p>
|
||
<motion.h2
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
||
transition={{ duration: 0.6, delay: 0.1 }}
|
||
className="text-vesta-dark text-3xl md:text-5xl font-serif font-light"
|
||
>
|
||
{t('title')}
|
||
</motion.h2>
|
||
</div>
|
||
|
||
{/* Grid */}
|
||
<div className="grid md:grid-cols-2 gap-6">
|
||
{amenities.map((item, i) => {
|
||
const Icon = item.icon
|
||
return (
|
||
<motion.div
|
||
key={item.key}
|
||
initial={{ opacity: 0, y: 30 }}
|
||
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
||
transition={{ duration: 0.6, delay: 0.15 * i }}
|
||
className="relative rounded-2xl overflow-hidden group cursor-default"
|
||
>
|
||
{/* Arka plan görseli */}
|
||
<div className="relative aspect-[16/9]">
|
||
<Image
|
||
src={item.image}
|
||
alt={t(item.key)}
|
||
fill
|
||
className="object-cover transition-transform duration-700 group-hover:scale-105"
|
||
/>
|
||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" />
|
||
</div>
|
||
|
||
{/* İçerik */}
|
||
<div className="absolute bottom-0 left-0 right-0 p-6">
|
||
<div className="flex items-center gap-3 mb-2">
|
||
<Icon className="w-4 h-4 text-white/70" />
|
||
<h3 className="text-white font-medium text-lg">{t(item.key)}</h3>
|
||
</div>
|
||
<p className="text-white/60 text-sm leading-relaxed max-w-md">
|
||
{t(item.descKey)}
|
||
</p>
|
||
</div>
|
||
</motion.div>
|
||
)
|
||
})}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|