160 lines
5.1 KiB
TypeScript
160 lines
5.1 KiB
TypeScript
/**
|
|
* Navigation Component
|
|
* Styled following Netwerk Digitaal Erfgoed (NDE) house style
|
|
* With bilingual support (NL/EN)
|
|
*/
|
|
|
|
import { useState, useRef, useEffect } from 'react';
|
|
import { Link, useLocation } from 'react-router-dom';
|
|
import { useAuth } from '../../contexts/AuthContext';
|
|
import { useLanguage, translations } from '../../contexts/LanguageContext';
|
|
import './Navigation.css';
|
|
|
|
export function Navigation() {
|
|
const location = useLocation();
|
|
const { user, logout } = useAuth();
|
|
const { language, toggleLanguage } = useLanguage();
|
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
const userMenuRef = useRef<HTMLDivElement>(null);
|
|
const mobileMenuRef = useRef<HTMLDivElement>(null);
|
|
|
|
// Close menus when clicking outside
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (userMenuRef.current && !userMenuRef.current.contains(event.target as Node)) {
|
|
setUserMenuOpen(false);
|
|
}
|
|
if (mobileMenuRef.current && !mobileMenuRef.current.contains(event.target as Node)) {
|
|
setMobileMenuOpen(false);
|
|
}
|
|
};
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
}, []);
|
|
|
|
// Close mobile menu on route change
|
|
useEffect(() => {
|
|
setMobileMenuOpen(false);
|
|
}, [location.pathname]);
|
|
|
|
const isActive = (path: string) => {
|
|
return location.pathname === path;
|
|
};
|
|
|
|
// Get translated nav text
|
|
const t = (key: keyof typeof translations.nav) => {
|
|
return language === 'en' ? translations.nav[key].en : translations.nav[key].nl;
|
|
};
|
|
|
|
return (
|
|
<nav className="navigation">
|
|
<div className="nav-container">
|
|
<Link to="/" className="nav-brand">
|
|
{/* NDE Logo - Blue sunburst "e" icon */}
|
|
<img
|
|
src="/nde-icon-square.png"
|
|
alt="Netwerk Digitaal Erfgoed Logo"
|
|
className="nav-logo"
|
|
/>
|
|
<span className="nav-title">Bronhouder</span>
|
|
</Link>
|
|
|
|
<div className="nav-links">
|
|
<Link
|
|
to="/"
|
|
className={`nav-link ${isActive('/') ? 'active' : ''}`}
|
|
>
|
|
{t('home')}
|
|
</Link>
|
|
<Link
|
|
to="/visualize"
|
|
className={`nav-link ${isActive('/visualize') ? 'active' : ''}`}
|
|
>
|
|
{t('visualize')}
|
|
</Link>
|
|
<Link
|
|
to="/database"
|
|
className={`nav-link ${isActive('/database') ? 'active' : ''}`}
|
|
>
|
|
{t('database')}
|
|
</Link>
|
|
<Link
|
|
to="/query-builder"
|
|
className={`nav-link ${isActive('/query-builder') ? 'active' : ''}`}
|
|
>
|
|
{t('query')}
|
|
</Link>
|
|
<Link
|
|
to="/linkml"
|
|
className={`nav-link ${isActive('/linkml') ? 'active' : ''}`}
|
|
>
|
|
{t('linkml')}
|
|
</Link>
|
|
<Link
|
|
to="/ontology"
|
|
className={`nav-link ${isActive('/ontology') ? 'active' : ''}`}
|
|
>
|
|
{t('ontology')}
|
|
</Link>
|
|
<Link
|
|
to="/map"
|
|
className={`nav-link ${isActive('/map') ? 'active' : ''}`}
|
|
>
|
|
{t('map')}
|
|
</Link>
|
|
<Link
|
|
to="/stats"
|
|
className={`nav-link ${isActive('/stats') ? 'active' : ''}`}
|
|
>
|
|
{t('stats')}
|
|
</Link>
|
|
<Link
|
|
to="/settings"
|
|
className={`nav-link ${isActive('/settings') ? 'active' : ''}`}
|
|
>
|
|
{t('settings')}
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Language Toggle */}
|
|
<button
|
|
className="nav-lang-toggle"
|
|
onClick={toggleLanguage}
|
|
aria-label={language === 'nl' ? 'Switch to English' : 'Schakel naar Nederlands'}
|
|
title={language === 'nl' ? 'Switch to English' : 'Schakel naar Nederlands'}
|
|
>
|
|
<span className={language === 'nl' ? 'lang-active' : 'lang-inactive'}>NL</span>
|
|
<span className="lang-separator">|</span>
|
|
<span className={language === 'en' ? 'lang-active' : 'lang-inactive'}>EN</span>
|
|
</button>
|
|
|
|
{/* User Account Dropdown */}
|
|
{user && (
|
|
<div className="nav-user" ref={userMenuRef}>
|
|
<button
|
|
className="nav-user-btn"
|
|
onClick={() => setUserMenuOpen(!userMenuOpen)}
|
|
aria-expanded={userMenuOpen}
|
|
aria-haspopup="true"
|
|
>
|
|
<span className="nav-user-icon">👤</span>
|
|
<span className="nav-user-name">{user.username}</span>
|
|
<span className="nav-user-chevron">{userMenuOpen ? '▲' : '▼'}</span>
|
|
</button>
|
|
{userMenuOpen && (
|
|
<div className="nav-user-menu">
|
|
<div className="nav-user-info">
|
|
<span className="nav-user-role">{user.role}</span>
|
|
</div>
|
|
<button onClick={logout} className="nav-user-logout">
|
|
{t('signOut')}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|