Files
Puechberty Arthur 49fd31f4db first commit
2026-03-30 23:07:36 +02:00

137 lines
5.2 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { useLocale } from './LocaleProvider';
import { ts } from '@/lib/i18n';
import { LOCALES, Locale } from '@/lib/i18n';
const NAV_ITEMS = [
{ key: 'nav_home' as const, href: '#hero' },
{ key: 'nav_calendar' as const, href: '#calendar' },
{ key: 'nav_fullmoons' as const, href: '#fullmoons' },
{ key: 'nav_simulator' as const, href: '#simulator' },
{ key: 'nav_articles' as const, href: '#articles' },
{ key: 'nav_quiz' as const, href: '#quiz' },
];
export default function Navigation() {
const { locale, setLocale } = useLocale();
const [scrolled, setScrolled] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const [langOpen, setLangOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 50);
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
return (
<>
<header
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
scrolled ? 'bg-[rgba(10,10,26,0.95)] backdrop-blur-xl shadow-lg shadow-indigo-500/5' : 'bg-transparent'
}`}
>
<nav className="max-w-7xl mx-auto px-4 py-3 flex items-center justify-between">
<a href="#hero" className="flex items-center gap-2 text-lg font-bold text-white">
<span className="text-2xl">🌕</span>
<span className="hidden sm:inline gradient-text-brand">
Moon Phases
</span>
</a>
{/* Desktop nav */}
<div className="hidden md:flex items-center gap-1">
{NAV_ITEMS.map((item) => (
<a key={item.key} href={item.href} className="nav-link">
{ts(item.key, locale)}
</a>
))}
</div>
<div className="flex items-center gap-2">
{/* Language selector */}
<div className="relative">
<button
onClick={() => setLangOpen(!langOpen)}
className="flex items-center gap-1 px-3 py-1.5 rounded-full text-sm bg-white/5 border border-white/10 hover:border-indigo-400/50 transition-all"
aria-label="Select language"
>
{LOCALES.find(l => l.code === locale)?.flag} <span className="hidden sm:inline text-xs uppercase">{locale}</span>
</button>
{langOpen && (
<div className="absolute right-0 top-full mt-2 w-48 glass-card p-2 grid grid-cols-2 gap-1 max-h-64 overflow-y-auto">
{LOCALES.map((l) => (
<button
key={l.code}
onClick={() => { setLocale(l.code as Locale); setLangOpen(false); }}
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-all hover:bg-indigo-500/20 ${
locale === l.code ? 'bg-indigo-500/20 text-indigo-300' : 'text-white/70'
}`}
>
<span>{l.flag}</span>
<span className="truncate">{l.name}</span>
</button>
))}
</div>
)}
</div>
{/* Mobile menu button */}
<button
onClick={() => setMenuOpen(!menuOpen)}
className="md:hidden p-2 rounded-lg hover:bg-white/10 transition-all"
aria-label="Menu"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{menuOpen ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
</nav>
{/* Mobile menu */}
{menuOpen && (
<div className="md:hidden bg-[rgba(10,10,26,0.98)] backdrop-blur-xl border-t border-white/10 px-4 py-4">
{NAV_ITEMS.map((item) => (
<a
key={item.key}
href={item.href}
onClick={() => setMenuOpen(false)}
className="block py-3 px-4 text-white/70 hover:text-indigo-300 hover:bg-indigo-500/10 rounded-lg transition-all"
>
{ts(item.key, locale)}
</a>
))}
</div>
)}
</header>
{/* Mobile bottom nav */}
<div className="mobile-nav">
{NAV_ITEMS.slice(0, 5).map((item) => (
<a
key={item.key}
href={item.href}
className="flex flex-col items-center gap-0.5 text-xs text-white/50 hover:text-indigo-300 transition-all py-1"
>
<span className="text-base">
{item.key === 'nav_home' ? '🏠' :
item.key === 'nav_calendar' ? '📅' :
item.key === 'nav_fullmoons' ? '🌕' :
item.key === 'nav_simulator' ? '🔭' : '🌐'}
</span>
<span className="truncate max-w-15">{ts(item.key, locale)}</span>
</a>
))}
</div>
</>
);
}