feat: complete initial project setup with i18n and standalone config
This commit is contained in:
123
components/Footer.tsx
Normal file
123
components/Footer.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
'use client';
|
||||
|
||||
import { Link } from '@/i18n/routing';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-aegean-dark text-bone py-20 px-6 font-sans">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Top Centered Section */}
|
||||
<div className="text-center mb-20">
|
||||
<h2 className="text-5xl md:text-7xl font-serif tracking-[0.2em] text-sand mb-4">SALMAKIS</h2>
|
||||
<p className="text-[10px] tracking-[0.4em] uppercase opacity-60 mb-10">
|
||||
A Heritage of Excellence Since 1980.
|
||||
</p>
|
||||
|
||||
<div className="space-y-2 text-sm opacity-80 font-medium">
|
||||
<p>+90 252 316 65 06</p>
|
||||
<p>08:00 - 20:00</p>
|
||||
<p>salmakis@salmakis.com.tr</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Three Columns Section */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-16 text-center mb-24">
|
||||
{/* Column 1: Resort */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-xl font-serif text-sand tracking-wide">Salmakis Resort</h3>
|
||||
<div className="text-[10px] leading-relaxed tracking-widest uppercase opacity-60 space-y-1">
|
||||
<p>BARDAKÇI KOYU</p>
|
||||
<p>BODRUM/MUĞLA/TURKEY</p>
|
||||
</div>
|
||||
<div className="text-xs space-y-1 opacity-80">
|
||||
<p>+90 252 316 65 06</p>
|
||||
<p>+90 252 316 65 07</p>
|
||||
<p>+90 252 316 65 11</p>
|
||||
</div>
|
||||
<p className="text-[10px] opacity-40">salmakis@salmakis.com.tr</p>
|
||||
</div>
|
||||
|
||||
{/* Column 2: Villas */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-xl font-serif text-sand tracking-wide">Salmakis Villas</h3>
|
||||
<div className="text-[10px] leading-relaxed tracking-widest uppercase opacity-60 space-y-1">
|
||||
<p>BADEMLİK MEVKİİ</p>
|
||||
<p>KÜME EVLERİ NO 24</p>
|
||||
<p>BODRUM/MUĞLA/TURKEY</p>
|
||||
</div>
|
||||
<div className="text-xs space-y-1 opacity-80">
|
||||
<p>+90 252 316 27 38</p>
|
||||
<p>+90 252 316 28 77</p>
|
||||
<p>+90 532 731 78 04</p>
|
||||
<p>+90 252 316 27 37</p>
|
||||
</div>
|
||||
<p className="text-[10px] opacity-40">info@salmakisvillas.com</p>
|
||||
</div>
|
||||
|
||||
{/* Column 3: Yachting */}
|
||||
<div className="space-y-6">
|
||||
<h3 className="text-xl font-serif text-sand tracking-wide">Salmakis Yachting</h3>
|
||||
<div className="text-[10px] leading-relaxed tracking-widest uppercase opacity-60 space-y-1">
|
||||
<p>KUMBAHÇE MAH. İÇMELER CAD.</p>
|
||||
<p>NO 28/1</p>
|
||||
<p>BODRUM/MUĞLA/TURKEY</p>
|
||||
</div>
|
||||
<div className="text-xs space-y-1 opacity-80">
|
||||
<p>+90 252 316 27 38</p>
|
||||
<p>+90 252 316 28 77</p>
|
||||
<p>+90 252 316 27 37</p>
|
||||
</div>
|
||||
<p className="text-[10px] opacity-40">info@salmakisyachting.com</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Socials Section */}
|
||||
<div className="flex flex-col md:flex-row justify-end items-center gap-6 mb-12 border-t border-white/5 pt-12">
|
||||
<span className="text-[10px] font-bold tracking-[0.3em] uppercase opacity-60">FOLLOW US</span>
|
||||
<div className="flex items-center space-x-6">
|
||||
{/* Instagram */}
|
||||
<svg className="w-5 h-5 opacity-80 hover:opacity-100 cursor-pointer transition-opacity" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
||||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
|
||||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
||||
</svg>
|
||||
{/* Facebook */}
|
||||
<svg className="w-5 h-5 opacity-80 hover:opacity-100 cursor-pointer transition-opacity" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path>
|
||||
</svg>
|
||||
{/* Play/Video */}
|
||||
<svg className="w-5 h-5 opacity-80 hover:opacity-100 cursor-pointer transition-opacity" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<polygon points="10 8 16 12 10 16 10 8"></polygon>
|
||||
</svg>
|
||||
{/* LinkedIn */}
|
||||
<svg className="w-5 h-5 opacity-80 hover:opacity-100 cursor-pointer transition-opacity" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
|
||||
<rect x="2" y="9" width="4" height="12"></rect>
|
||||
<circle cx="4" cy="4" r="2"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Bar */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-center gap-8 pt-12 border-t border-white/5">
|
||||
<div className="flex flex-wrap justify-center gap-8 text-[9px] font-bold tracking-[0.2em] uppercase opacity-50">
|
||||
<Link href="#" className="hover:opacity-100 transition-opacity">LEGAL & PRIVACY</Link>
|
||||
<Link href="#" className="hover:opacity-100 transition-opacity">COOKIES</Link>
|
||||
<Link href="#" className="hover:opacity-100 transition-opacity">SITEMAP</Link>
|
||||
<Link href="#" className="hover:opacity-100 transition-opacity">COOKIES SETTINGS</Link>
|
||||
</div>
|
||||
|
||||
<div className="text-right space-y-2">
|
||||
<p className="text-[9px] font-bold tracking-[0.2em] uppercase opacity-40">
|
||||
© SALMAKIS 2026 ALL RIGHTS RESERVED
|
||||
</p>
|
||||
<p className="text-[9px] font-bold tracking-[0.2em] uppercase opacity-40">
|
||||
CREATED BY <span className="text-sand/80">AYRISTECH</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
74
components/Hero.tsx
Normal file
74
components/Hero.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Link } from '@/i18n/routing';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Hero() {
|
||||
const t = useTranslations('Index');
|
||||
|
||||
return (
|
||||
<section className="relative h-screen flex items-center justify-center overflow-hidden">
|
||||
{/* Background with Overlay */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<Image
|
||||
src="https://images.unsplash.com/photo-1542718610-a1d656d1884c?q=80&w=2070&auto=format&fit=crop"
|
||||
alt="Luxury Villa"
|
||||
fill
|
||||
priority
|
||||
className="object-cover scale-105"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/30 bg-gradient-to-b from-black/40 via-transparent to-bone/10" />
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 text-center px-6 max-w-4xl">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
>
|
||||
<span className="inline-block mb-4 text-bone text-sm font-bold tracking-[0.3em] uppercase opacity-90">
|
||||
Salmakis Collection
|
||||
</span>
|
||||
<h1 className="text-5xl md:text-8xl font-serif text-bone leading-tight mb-6">
|
||||
{t('title')}
|
||||
</h1>
|
||||
<p className="text-lg md:text-xl text-bone/90 font-sans max-w-2xl mx-auto mb-10 leading-relaxed">
|
||||
{t('description')}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<Link
|
||||
href="/#villas"
|
||||
className="group relative px-8 py-4 bg-salmakis-blue text-white rounded-full font-bold overflow-hidden transition-all duration-300 hover:shadow-xl hover:shadow-salmakis-blue/20"
|
||||
>
|
||||
<span className="relative z-10 flex items-center space-x-2">
|
||||
<span>{t('explore')}</span>
|
||||
<ChevronRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
|
||||
</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/contact"
|
||||
className="px-8 py-4 bg-white/10 backdrop-blur-md border border-white/20 text-white rounded-full font-bold hover:bg-white/20 transition-all duration-300"
|
||||
>
|
||||
İletişime Geç
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Scroll indicator */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 1, duration: 1 }}
|
||||
className="absolute bottom-10 left-1/2 -translate-x-1/2"
|
||||
>
|
||||
<div className="w-[1px] h-20 bg-gradient-to-b from-white to-transparent" />
|
||||
</motion.div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
109
components/Navbar.tsx
Normal file
109
components/Navbar.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
'use client';
|
||||
|
||||
import { useTranslations, useLocale } from 'next-intl';
|
||||
import { Link, usePathname, useRouter } from '@/i18n/routing';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { Menu, X, Globe } from 'lucide-react';
|
||||
|
||||
function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export default function Navbar() {
|
||||
const t = useTranslations('Navbar');
|
||||
const locale = useLocale();
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setIsScrolled(window.scrollY > 20);
|
||||
};
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const toggleLanguage = () => {
|
||||
const nextLocale = locale === 'tr' ? 'en' : 'tr';
|
||||
router.replace(pathname, { locale: nextLocale });
|
||||
};
|
||||
|
||||
const navLinks = [
|
||||
{ href: '/', label: t('villas') },
|
||||
{ href: '/about', label: t('about') },
|
||||
{ href: '/contact', label: t('contact') },
|
||||
];
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={cn(
|
||||
'fixed top-0 left-0 right-0 z-50 transition-all duration-300 px-6 py-4',
|
||||
isScrolled ? 'glass-nav py-3' : 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
<div className="max-w-7xl mx-auto flex items-center justify-between">
|
||||
<Link href="/" className="text-2xl font-serif font-bold tracking-tight text-aegean-dark">
|
||||
SALMAKIS <span className="text-salmakis-blue">VILLAS</span>
|
||||
</Link>
|
||||
|
||||
{/* Desktop Nav */}
|
||||
<div className="hidden md:flex items-center space-x-8">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href as any}
|
||||
className="text-sm font-medium hover:text-salmakis-blue transition-colors"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
<button
|
||||
onClick={toggleLanguage}
|
||||
className="flex items-center space-x-1 text-xs font-bold uppercase tracking-widest border border-aegean-dark/20 px-3 py-1 rounded-full hover:bg-aegean-dark hover:text-bone transition-all"
|
||||
>
|
||||
<Globe className="w-3 h-3" />
|
||||
<span>{locale === 'tr' ? 'EN' : 'TR'}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Toggle */}
|
||||
<button
|
||||
className="md:hidden text-aegean-dark"
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
>
|
||||
{isMobileMenuOpen ? <X /> : <Menu />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
{isMobileMenuOpen && (
|
||||
<div className="md:hidden absolute top-full left-0 right-0 bg-bone border-b border-aegean-dark/10 p-6 flex flex-col space-y-4 animate-in fade-in slide-in-from-top-4">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href as any}
|
||||
className="text-lg font-serif"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
<button
|
||||
onClick={() => {
|
||||
toggleLanguage();
|
||||
setIsMobileMenuOpen(false);
|
||||
}}
|
||||
className="flex items-center space-x-2 text-sm font-bold uppercase py-2"
|
||||
>
|
||||
<Globe className="w-4 h-4" />
|
||||
<span>{locale === 'tr' ? 'English' : 'Türkçe'}</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
76
components/VillaCard.tsx
Normal file
76
components/VillaCard.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
'use client';
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { Villa } from '@/data/villas';
|
||||
import { Link } from '@/i18n/routing';
|
||||
import { Users, Bed, Droplets, MapPin } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
|
||||
interface VillaCardProps {
|
||||
villa: Villa;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export default function VillaCard({ villa, index }: VillaCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6, delay: index * 0.1 }}
|
||||
className="villa-card group bg-white rounded-2xl overflow-hidden shadow-sm"
|
||||
>
|
||||
<Link href={`/villas/${villa.slug}` as any}>
|
||||
<div className="relative aspect-[4/5] overflow-hidden">
|
||||
<Image
|
||||
src={villa.images[0]}
|
||||
alt={villa.name}
|
||||
fill
|
||||
className="object-cover transition-transform duration-700 group-hover:scale-110"
|
||||
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
||||
/>
|
||||
<div className="absolute top-4 left-4 bg-white/90 backdrop-blur-sm px-3 py-1 rounded-full text-[10px] font-bold tracking-widest uppercase text-aegean-dark">
|
||||
Portfolio
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-6 bg-gradient-to-t from-black/60 to-transparent">
|
||||
<div className="flex items-center text-white/90 text-xs mb-1">
|
||||
<MapPin className="w-3 h-3 mr-1" />
|
||||
{villa.location}
|
||||
</div>
|
||||
<h3 className="text-2xl font-serif text-white">{villa.name}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<div className="p-6">
|
||||
<div className="flex justify-between items-center mb-6 border-b border-aegean-dark/5 pb-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex flex-col items-center">
|
||||
<Users className="w-4 h-4 text-salmakis-blue mb-1" />
|
||||
<span className="text-[10px] uppercase font-bold text-aegean-dark/40">{villa.capacity} Kişi</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<Bed className="w-4 h-4 text-salmakis-blue mb-1" />
|
||||
<span className="text-[10px] uppercase font-bold text-aegean-dark/40">{villa.bedrooms} Oda</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<Droplets className="w-4 h-4 text-salmakis-blue mb-1" />
|
||||
<span className="text-[10px] uppercase font-bold text-aegean-dark/40">Havuz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<span className="text-[10px] uppercase font-bold text-aegean-dark/40 block">Gecelik</span>
|
||||
<span className="text-lg font-serif font-bold text-salmakis-blue">€{villa.priceLow} - €{villa.priceHigh}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href={`/villas/${villa.slug}` as any}
|
||||
className="w-full block py-3 text-center rounded-xl border border-aegean-dark/10 text-sm font-bold uppercase tracking-widest bg-aegean-dark text-white hover:bg-salmakis-blue transition-all duration-300 shadow-lg shadow-aegean-dark/10"
|
||||
>
|
||||
Detayları İncele
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
168
components/VillaGallery.tsx
Normal file
168
components/VillaGallery.tsx
Normal file
@@ -0,0 +1,168 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { X, ChevronLeft, ChevronRight, Maximize2 } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
|
||||
interface VillaGalleryProps {
|
||||
images: string[];
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default function VillaGallery({ images, name }: VillaGalleryProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
const openLightbox = (index: number) => {
|
||||
setCurrentIndex(index);
|
||||
setIsOpen(true);
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
|
||||
const closeLightbox = () => {
|
||||
setIsOpen(false);
|
||||
document.body.style.overflow = 'auto';
|
||||
};
|
||||
|
||||
const nextImage = () => {
|
||||
setCurrentIndex((prev) => (prev + 1) % images.length);
|
||||
};
|
||||
|
||||
const prevImage = () => {
|
||||
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 grid-rows-2 h-[400px] md:h-[600px] gap-4 rounded-3xl overflow-hidden shadow-2xl">
|
||||
{/* Main large image */}
|
||||
<div
|
||||
className="md:col-span-2 md:row-span-2 relative group overflow-hidden cursor-zoom-in"
|
||||
onClick={() => openLightbox(0)}
|
||||
>
|
||||
<Image
|
||||
src={images[0]}
|
||||
fill
|
||||
className="object-cover transition-transform duration-700 group-hover:scale-105"
|
||||
alt={`${name} 1`}
|
||||
priority
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
||||
<Maximize2 className="text-white w-8 h-8" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Second image */}
|
||||
<div
|
||||
className="md:col-span-1 relative group overflow-hidden cursor-zoom-in"
|
||||
onClick={() => openLightbox(1)}
|
||||
>
|
||||
{images[1] ? (
|
||||
<Image src={images[1]} fill className="object-cover transition-transform duration-700 group-hover:scale-105" alt={`${name} 2`} />
|
||||
) : (
|
||||
<div className="w-full h-full bg-aegean-dark/5" />
|
||||
)}
|
||||
<div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
||||
<Maximize2 className="text-white w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Third image */}
|
||||
<div
|
||||
className="md:col-span-1 relative group overflow-hidden cursor-zoom-in"
|
||||
onClick={() => openLightbox(2)}
|
||||
>
|
||||
{images[2] ? (
|
||||
<Image src={images[2]} fill className="object-cover transition-transform duration-700 group-hover:scale-105" alt={`${name} 3`} />
|
||||
) : (
|
||||
<div className="w-full h-full bg-aegean-dark/5" />
|
||||
)}
|
||||
<div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
||||
<Maximize2 className="text-white w-6 h-6" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fourth image with overlay if more exists */}
|
||||
<div
|
||||
className="md:col-span-2 relative group overflow-hidden cursor-zoom-in"
|
||||
onClick={() => openLightbox(3)}
|
||||
>
|
||||
{images[3] ? (
|
||||
<Image src={images[3]} fill className="object-cover transition-transform duration-700 group-hover:scale-105" alt={`${name} 4`} />
|
||||
) : (
|
||||
<div className="w-full h-full bg-aegean-dark/5" />
|
||||
)}
|
||||
|
||||
{images.length > 4 && (
|
||||
<div className="absolute inset-0 bg-black/50 flex flex-col items-center justify-center text-white backdrop-blur-[2px] group-hover:bg-black/40 transition-all">
|
||||
<span className="text-3xl font-serif">+{images.length - 4}</span>
|
||||
<span className="text-[10px] font-bold uppercase tracking-widest mt-2">Daha Fazla Fotoğraf</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
|
||||
{! (images.length > 4) && <Maximize2 className="text-white w-8 h-8" />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lightbox Overlay */}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-[100] bg-black/95 flex items-center justify-center p-4 md:p-8"
|
||||
>
|
||||
<button
|
||||
onClick={closeLightbox}
|
||||
className="absolute top-8 right-8 text-white/70 hover:text-white z-50 transition-colors"
|
||||
>
|
||||
<X className="w-8 h-8" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={prevImage}
|
||||
className="absolute left-4 md:left-8 text-white/70 hover:text-white z-50 p-2 rounded-full hover:bg-white/10 transition-all"
|
||||
>
|
||||
<ChevronLeft className="w-10 h-10" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={nextImage}
|
||||
className="absolute right-4 md:right-8 text-white/70 hover:text-white z-50 p-2 rounded-full hover:bg-white/10 transition-all"
|
||||
>
|
||||
<ChevronRight className="w-10 h-10" />
|
||||
</button>
|
||||
|
||||
<motion.div
|
||||
key={currentIndex}
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.9 }}
|
||||
className="relative w-full h-full max-w-6xl max-h-[80vh]"
|
||||
>
|
||||
{images[currentIndex] ? (
|
||||
<Image
|
||||
src={images[currentIndex]}
|
||||
fill
|
||||
className="object-contain"
|
||||
alt={`${name} Full`}
|
||||
quality={100}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-white/50">Görsel Yüklenemedi</div>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 text-white/60 text-sm font-medium tracking-widest uppercase">
|
||||
{currentIndex + 1} / {images.length} — {name}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user