145 lines
3.9 KiB
TypeScript
145 lines
3.9 KiB
TypeScript
import React from 'react';
|
|
import type { Translation } from '@/types/i18n';
|
|
|
|
// Fonction utilitaire simple pour combiner les classes
|
|
const mergeClasses = (...classes: (string | undefined | null | false)[]): string => {
|
|
return classes.filter(Boolean).join(' ');
|
|
};
|
|
|
|
interface NavLinksProps {
|
|
translations: Translation['navigation'];
|
|
scrolled?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
interface NavLinkProps {
|
|
href: string;
|
|
children: React.ReactNode;
|
|
isActive?: boolean;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
const NavLink: React.FC<NavLinkProps> = ({ href, children, isActive = false, onClick }) => {
|
|
return (
|
|
<a
|
|
href={href}
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
onClick?.();
|
|
}}
|
|
className={mergeClasses(
|
|
// Base styles
|
|
'relative px-4 py-2.5 text-sm font-medium transition-all duration-200 rounded-xl',
|
|
'focus:outline-none focus:ring-2 focus:ring-blue-400/50',
|
|
|
|
// États conditionnels
|
|
isActive
|
|
? 'text-white bg-white/15 shadow-sm backdrop-blur-sm border border-white/20'
|
|
: 'text-white/80 hover:text-white hover:bg-white/10'
|
|
)}
|
|
>
|
|
<span className="relative z-10">{children}</span>
|
|
|
|
{/* Indicateur actif moderne */}
|
|
{isActive && (
|
|
<div className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-1 h-1 bg-blue-300 rounded-full" />
|
|
)}
|
|
</a>
|
|
);
|
|
};
|
|
|
|
export const NavLinks: React.FC<NavLinksProps> = ({ translations, className }) => {
|
|
const [activeSection, setActiveSection] = React.useState<string>('home');
|
|
|
|
// Observer pour détecter la section active (simplifié)
|
|
React.useEffect(() => {
|
|
const handleScroll = () => {
|
|
const scrollPosition = window.scrollY;
|
|
|
|
// Si on est en haut de la page
|
|
if (scrollPosition < 200) {
|
|
setActiveSection('home');
|
|
return;
|
|
}
|
|
|
|
// Détection des sections
|
|
const sections = ['services', 'about'];
|
|
let currentSection = 'home';
|
|
|
|
sections.forEach((sectionId) => {
|
|
const element = document.getElementById(sectionId);
|
|
if (element) {
|
|
const rect = element.getBoundingClientRect();
|
|
if (rect.top <= 200 && rect.bottom >= 200) {
|
|
currentSection = sectionId;
|
|
}
|
|
}
|
|
});
|
|
|
|
setActiveSection(currentSection);
|
|
};
|
|
|
|
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
handleScroll();
|
|
|
|
return () => window.removeEventListener('scroll', handleScroll);
|
|
}, []);
|
|
|
|
const handleNavClick = (sectionId: string) => {
|
|
if (sectionId === 'home') {
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
} else if (sectionId === 'contact') {
|
|
window.location.href = 'mailto:contact@la-banquise.fr';
|
|
} else {
|
|
const element = document.getElementById(sectionId);
|
|
if (element) {
|
|
const navHeight = 64; // Hauteur de la navbar
|
|
const elementPosition = element.offsetTop - navHeight;
|
|
window.scrollTo({
|
|
top: elementPosition,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<nav className={mergeClasses(
|
|
'hidden md:flex items-center space-x-2',
|
|
className
|
|
)}>
|
|
<NavLink
|
|
href="#home"
|
|
isActive={activeSection === 'home'}
|
|
onClick={() => handleNavClick('home')}
|
|
>
|
|
{translations.home}
|
|
</NavLink>
|
|
|
|
<NavLink
|
|
href="#services"
|
|
isActive={activeSection === 'services'}
|
|
onClick={() => handleNavClick('services')}
|
|
>
|
|
{translations.services}
|
|
</NavLink>
|
|
|
|
<NavLink
|
|
href="#about"
|
|
isActive={activeSection === 'about'}
|
|
onClick={() => handleNavClick('about')}
|
|
>
|
|
{translations.about}
|
|
</NavLink>
|
|
|
|
<NavLink
|
|
href="mailto:contact@la-banquise.fr"
|
|
isActive={false}
|
|
onClick={() => handleNavClick('contact')}
|
|
>
|
|
{translations.contact}
|
|
</NavLink>
|
|
</nav>
|
|
);
|
|
};
|