Initialize ZUJ OL Apps website with React + TypeScript + Vite
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Sun, Moon, Globe, ExternalLink, Menu, X } from 'lucide-react';
|
||||
import { useApp } from '../contexts/AppContext';
|
||||
import { useI18n } from '../hooks/useI18n';
|
||||
import { siteData } from '../data/siteData';
|
||||
|
||||
export default function Nav() {
|
||||
const { theme, mobileMenuOpen, toggleTheme, toggleLang, openMobileMenu, closeMobileMenu } = useApp();
|
||||
const { t, bi } = useI18n();
|
||||
const location = useLocation();
|
||||
const currentPath = '/' + location.pathname.slice(1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav className="nav">
|
||||
<div className="nav-inner">
|
||||
<Link to="/" className="nav-brand">
|
||||
<span className="nav-brand-icon">Z</span>
|
||||
{bi(siteData.brand.name)}
|
||||
</Link>
|
||||
<div className="nav-links">
|
||||
{siteData.nav.map(n => {
|
||||
const navPath = n.hash.slice(2) || '/';
|
||||
const isActive = currentPath === navPath ||
|
||||
(navPath === '/' && currentPath === '');
|
||||
return (
|
||||
<Link
|
||||
key={n.id}
|
||||
to={navPath === '/' ? '/' : navPath}
|
||||
className={`nav-link${isActive ? ' active' : ''}`}
|
||||
>
|
||||
{bi(n.label)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="nav-actions">
|
||||
<button className="nav-btn" onClick={toggleTheme} title={t('nav.theme')}>
|
||||
{theme === 'dark' ? <Sun size={18} /> : <Moon size={18} />}
|
||||
</button>
|
||||
<button className="nav-btn" onClick={toggleLang} title={t('nav.lang')}>
|
||||
<Globe size={16} />
|
||||
</button>
|
||||
<a href={siteData.brand.github} target="_blank" className="nav-btn" title="GitHub">
|
||||
<ExternalLink size={18} />
|
||||
</a>
|
||||
<button
|
||||
className="nav-btn nav-mobile-toggle"
|
||||
onClick={mobileMenuOpen ? closeMobileMenu : openMobileMenu}
|
||||
aria-label="Menu"
|
||||
aria-expanded={mobileMenuOpen}
|
||||
>
|
||||
{mobileMenuOpen ? <X size={18} /> : <Menu size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div className={`nav-mobile-menu${mobileMenuOpen ? ' open' : ''}`}>
|
||||
{siteData.nav.map(n => {
|
||||
const navPath = n.hash.slice(2) || '/';
|
||||
return (
|
||||
<Link
|
||||
key={n.id}
|
||||
to={navPath === '/' ? '/' : navPath}
|
||||
className="nav-link"
|
||||
onClick={closeMobileMenu}
|
||||
>
|
||||
{bi(n.label)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user