116 lines
5.4 KiB
TypeScript
116 lines
5.4 KiB
TypeScript
import { useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { LANGUAGES } from '../i18n'
|
|
|
|
interface Props {
|
|
theme: 'light' | 'dark'
|
|
onToggleTheme: () => void
|
|
}
|
|
|
|
export default function Header({ theme, onToggleTheme }: Props) {
|
|
const { t, i18n } = useTranslation()
|
|
const [langOpen, setLangOpen] = useState(false)
|
|
const [menuOpen, setMenuOpen] = useState(false)
|
|
|
|
const currentLang = LANGUAGES.find(l => l.code === i18n.language) ?? LANGUAGES[0]
|
|
|
|
const navLinks = [
|
|
{ href: '#about', label: t('nav_about') },
|
|
{ href: '#games', label: t('nav_games') },
|
|
{ href: '#partnership', label: t('nav_partnership') },
|
|
{ href: '#contact', label: t('nav_contact') },
|
|
]
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 bg-white/80 dark:bg-gray-950/80 backdrop-blur border-b border-gray-200 dark:border-gray-800">
|
|
<div className="max-w-6xl mx-auto px-4 h-16 flex items-center justify-between">
|
|
{/* Logo */}
|
|
<a href="#" className="flex items-center font-bold text-xl tracking-tight">
|
|
<span className="text-orange-500">Kai</span><span className="text-gray-900 dark:text-white">Soft</span>
|
|
</a>
|
|
|
|
{/* Desktop nav */}
|
|
<nav className="hidden md:flex items-center gap-6">
|
|
{navLinks.map(l => (
|
|
<a key={l.href} href={l.href}
|
|
className="text-sm font-medium text-gray-600 dark:text-gray-300 hover:text-orange-500 dark:hover:text-orange-400 transition-colors">
|
|
{l.label}
|
|
</a>
|
|
))}
|
|
</nav>
|
|
|
|
{/* Controls */}
|
|
<div className="flex items-center gap-2">
|
|
{/* Language selector */}
|
|
<div className="relative">
|
|
<button
|
|
onClick={() => setLangOpen(o => !o)}
|
|
className="flex items-center gap-1 px-3 py-1.5 rounded-lg text-sm font-medium text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
|
|
<span>{currentLang.label}</span>
|
|
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
</svg>
|
|
</button>
|
|
{langOpen && (
|
|
<div className="absolute right-0 mt-1 w-44 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg overflow-hidden z-50">
|
|
<div className="max-h-72 overflow-y-auto">
|
|
{LANGUAGES.map(lang => (
|
|
<button key={lang.code}
|
|
onClick={() => { i18n.changeLanguage(lang.code); setLangOpen(false) }}
|
|
className={`w-full text-left px-4 py-2.5 text-sm transition-colors
|
|
${lang.code === i18n.language
|
|
? 'bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400 font-semibold'
|
|
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800'}`}>
|
|
{lang.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Dark mode toggle */}
|
|
<button onClick={onToggleTheme}
|
|
className="p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
|
aria-label="Toggle theme">
|
|
{theme === 'dark' ? (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
|
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 8a4 4 0 100 8 4 4 0 000-8z" />
|
|
</svg>
|
|
) : (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
|
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
</svg>
|
|
)}
|
|
</button>
|
|
|
|
{/* Mobile menu toggle */}
|
|
<button onClick={() => setMenuOpen(o => !o)}
|
|
className="md:hidden p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
|
|
<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>
|
|
</div>
|
|
|
|
{/* Mobile nav */}
|
|
{menuOpen && (
|
|
<nav className="md:hidden border-t border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-950">
|
|
{navLinks.map(l => (
|
|
<a key={l.href} href={l.href}
|
|
onClick={() => setMenuOpen(false)}
|
|
className="block px-4 py-3 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-orange-500 dark:hover:text-orange-400 hover:bg-gray-50 dark:hover:bg-gray-900 transition-colors">
|
|
{l.label}
|
|
</a>
|
|
))}
|
|
</nav>
|
|
)}
|
|
</header>
|
|
)
|
|
}
|