229 lines
8.5 KiB
TypeScript
229 lines
8.5 KiB
TypeScript
'use client';
|
|
|
|
import { Link, usePathname, useRouter } from '@/i18n/routing';
|
|
import { useState, useEffect } from 'react';
|
|
import { useLocale, useTranslations } from 'next-intl';
|
|
import { motion, AnimatePresence, Variants } from 'framer-motion';
|
|
|
|
const menuVariants: Variants = {
|
|
closed: {
|
|
opacity: 0,
|
|
y: "-100%",
|
|
transition: {
|
|
duration: 0.8,
|
|
ease: [0.76, 0, 0.24, 1] as const
|
|
}
|
|
},
|
|
open: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.8,
|
|
ease: [0.76, 0, 0.24, 1] as const
|
|
}
|
|
}
|
|
};
|
|
|
|
const linkVariants: Variants = {
|
|
closed: { opacity: 0, y: 30 },
|
|
open: (i: number) => ({
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.7,
|
|
delay: 0.5 + i * 0.1,
|
|
ease: [0.215, 0.61, 0.355, 1] as const
|
|
}
|
|
}),
|
|
exit: {
|
|
opacity: 0,
|
|
y: 20,
|
|
transition: {
|
|
duration: 0.5,
|
|
ease: [0.215, 0.61, 0.355, 1] as const
|
|
}
|
|
}
|
|
};
|
|
|
|
export default function Navbar() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const pathname = usePathname();
|
|
const router = useRouter();
|
|
const locale = useLocale();
|
|
const t = useTranslations('Navbar');
|
|
|
|
// Close menu on route change
|
|
useEffect(() => {
|
|
setIsOpen(false);
|
|
}, [pathname]);
|
|
|
|
// Lock body scroll when menu is open
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
document.body.style.overflow = 'hidden';
|
|
} else {
|
|
document.body.style.overflow = 'unset';
|
|
}
|
|
}, [isOpen]);
|
|
|
|
const changeLocale = (nextLocale: string) => {
|
|
router.replace(pathname, { locale: nextLocale });
|
|
};
|
|
|
|
const navLinks = [
|
|
{ name: t('meira'), href: '/fleet/meira' },
|
|
{ name: t('princess'), href: '/fleet/princess-melda' },
|
|
{ name: t('queen'), href: '/fleet/queen-of-salmakis' },
|
|
{ name: t('dolce'), href: '/fleet/dolce-mare' },
|
|
{ name: t('sunworld'), href: '/fleet/sunworld-8' },
|
|
];
|
|
|
|
|
|
|
|
return (
|
|
<nav className="fixed top-0 w-full z-50 transition-all duration-300">
|
|
{/* Background Layer (Transparent initially, solid on scroll could be added later) */}
|
|
<div className="absolute inset-0 bg-white/90 backdrop-blur-md border-b border-outline-variant/10 shadow-sm" />
|
|
|
|
<div className="relative w-full flex items-center justify-between px-6 md:px-12 py-6">
|
|
|
|
{/* Left: Hamburger (Mobile) / Placeholder (Desktop) */}
|
|
<div className="md:hidden">
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="relative z-[70] w-10 h-10 flex flex-col items-center justify-center gap-1.5 focus:outline-none"
|
|
>
|
|
<motion.span
|
|
animate={isOpen ? { rotate: 45, y: 8, backgroundColor: "#ffffff" } : { rotate: 0, y: 0, backgroundColor: "#06152D" }}
|
|
className="w-8 h-px block"
|
|
/>
|
|
<motion.span
|
|
animate={isOpen ? { opacity: 0 } : { opacity: 1 }}
|
|
className="w-8 h-px bg-primary block"
|
|
/>
|
|
<motion.span
|
|
animate={isOpen ? { rotate: -45, y: -6, backgroundColor: "#ffffff" } : { rotate: 0, y: 0, backgroundColor: "#06152D" }}
|
|
className="w-8 h-px block"
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Center: Logo */}
|
|
<div className="absolute left-1/2 -translate-x-1/2 flex flex-col items-center">
|
|
<Link href="/" className="group flex flex-col items-center">
|
|
<span className="font-headline text-3xl md:text-4xl tracking-[0.5em] text-primary group-hover:text-secondary transition-colors duration-700 uppercase mr-[-0.5em]">
|
|
SALMAKIS
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Right: Actions / Desktop Nav Wrapper */}
|
|
<div className="flex items-center space-x-8">
|
|
{/* Desktop Lang Switcher */}
|
|
<div className="hidden md:flex items-center font-label text-[10px] tracking-[0.2em] uppercase text-primary/40">
|
|
<button onClick={() => changeLocale('en')} className={`${locale === 'en' ? 'text-secondary font-bold' : ''}`}>EN</button>
|
|
<span className="mx-2 text-outline-variant">|</span>
|
|
<button onClick={() => changeLocale('tr')} className={`${locale === 'tr' ? 'text-secondary font-bold' : ''}`}>TR</button>
|
|
</div>
|
|
|
|
<Link href="/contact" className="hidden lg:block font-headline text-[10px] tracking-[0.3em] font-medium border border-primary/20 px-6 py-2.5 uppercase hover:bg-primary hover:text-white transition-all duration-500">
|
|
{t('contact') || 'Contact'}
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Desktop Navigation Row (Optional: Can stay below logo or be inline) */}
|
|
<div className="hidden md:flex relative justify-center border-t border-outline-variant/5 py-4">
|
|
<div className="flex items-center gap-x-12">
|
|
{navLinks.map((link) => {
|
|
const isActive = pathname === link.href;
|
|
return (
|
|
<Link
|
|
key={link.name}
|
|
href={link.href}
|
|
className={`font-headline text-[11px] tracking-[0.35em] font-medium uppercase transition-all duration-500 relative pb-1 group ${isActive ? 'text-primary' : 'text-primary/50 hover:text-primary'}`}
|
|
>
|
|
{link.name}
|
|
<motion.span
|
|
initial={false}
|
|
animate={isActive ? { width: "100%" } : { width: "0%" }}
|
|
className="absolute bottom-0 left-0 h-px bg-secondary"
|
|
/>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Menu Overlay */}
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<motion.div
|
|
variants={menuVariants}
|
|
initial="closed"
|
|
animate="open"
|
|
exit="closed"
|
|
className="fixed inset-0 z-[60] bg-primary flex flex-col overflow-hidden"
|
|
>
|
|
{/* Artistic Background Element */}
|
|
<div className="absolute top-0 right-0 w-[150%] h-full bg-[#050B15] -rotate-12 translate-x-1/2 pointer-events-none opacity-50" />
|
|
|
|
<div className="relative h-full flex flex-col px-8 pt-48 pb-12 justify-between">
|
|
{/* Links */}
|
|
<div className="flex flex-col space-y-8">
|
|
{navLinks.map((link, i) => (
|
|
<motion.div
|
|
key={link.name}
|
|
custom={i}
|
|
variants={linkVariants}
|
|
>
|
|
<Link
|
|
href={link.href}
|
|
className="font-headline text-3xl md:text-5xl tracking-[0.2em] text-white/90 hover:text-secondary uppercase transition-colors flex items-center gap-4 group"
|
|
>
|
|
<span className="text-secondary font-headline text-xs tracking-widest opacity-40 group-hover:opacity-100">0{i+1}</span>
|
|
{link.name}
|
|
</Link>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Bottom Info */}
|
|
<div className="grid grid-cols-2 gap-8 border-t border-white/10 pt-12">
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1, transition: { delay: 1 } }}
|
|
className="space-y-4"
|
|
>
|
|
<span className="font-label text-[10px] tracking-[0.3em] text-secondary uppercase">Quick Link</span>
|
|
<Link href="/contact" className="block text-white font-headline text-sm tracking-widest uppercase mb-4">Inquire Now</Link>
|
|
|
|
<div className="flex gap-4">
|
|
<button onClick={() => changeLocale('en')} className={`text-[10px] tracking-[0.2em] font-bold ${locale === 'en' ? 'text-secondary' : 'text-white/40'}`}>EN</button>
|
|
<button onClick={() => changeLocale('tr')} className={`text-[10px] tracking-[0.2em] font-bold ${locale === 'tr' ? 'text-secondary' : 'text-white/40'}`}>TR</button>
|
|
</div>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1, transition: { delay: 1.2 } }}
|
|
className="text-right space-y-4"
|
|
>
|
|
<span className="font-label text-[10px] tracking-[0.3em] text-secondary uppercase">Salmakis Yachting</span>
|
|
<div className="text-white/60 font-body text-xs leading-relaxed">
|
|
Bodrum, Mugla<br />
|
|
Turkish Riviera
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
|
|
|