feat: complete initial project setup with i18n and standalone config
This commit is contained in:
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user