website-front/banquise-website/src/components/ui/ModernLanguageSwitcher.tsx
sahamone bd42196f54
Some checks failed
Build / build-check (pull_request) Failing after 26s
refactoring & UI improvment
2025-07-10 18:35:45 +02:00

111 lines
3.9 KiB
TypeScript

import React, { useState } from 'react';
import { mergeClasses as cn } from '../../styles/designSystem';
import type { Language } from '../../types/i18n';
interface ModernLanguageSwitcherProps {
currentLanguage: Language;
onLanguageChange: (language: Language) => void;
availableLanguages: Language[];
}
export const ModernLanguageSwitcher: React.FC<ModernLanguageSwitcherProps> = ({
currentLanguage,
onLanguageChange,
availableLanguages
}) => {
const [isOpen, setIsOpen] = useState(false);
const languageConfig: Record<Language, { name: string; flag: string; nativeName: string }> = {
fr: { name: 'Français', flag: '🇫🇷', nativeName: 'FR' },
en: { name: 'English', flag: '🇬🇧', nativeName: 'EN' },
};
const currentConfig = languageConfig[currentLanguage];
return (
<div className="relative">
{/* Trigger Button */}
<button
onClick={() => setIsOpen(!isOpen)}
className={cn(
'flex items-center space-x-2 px-3 py-2 rounded-lg transition-all duration-200',
'bg-white/10 hover:bg-white/20 border border-white/20 hover:border-white/30',
'text-white text-sm font-medium',
'focus:outline-none focus:ring-2 focus:ring-banquise-blue-light/50',
'group'
)}
aria-expanded={isOpen}
aria-haspopup="listbox"
>
<span className="text-lg">{currentConfig.flag}</span>
<span className="hidden sm:inline">{currentConfig.nativeName}</span>
{/* Chevron Icon */}
<svg
className={cn(
'w-4 h-4 transition-transform duration-200',
isOpen ? 'rotate-180' : 'rotate-0'
)}
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>
{/* Dropdown Menu */}
{isOpen && (
<>
{/* Backdrop */}
<div
className="fixed inset-0 z-10"
onClick={() => setIsOpen(false)}
/>
{/* Menu */}
<div className={cn(
'absolute right-0 top-full mt-2 z-20',
'bg-white/95 backdrop-blur-xl rounded-xl shadow-2xl border border-white/20',
'min-w-[140px] py-2',
'animate-slideUp'
)}>
{availableLanguages.map((lang) => {
const config = languageConfig[lang];
const isSelected = lang === currentLanguage;
return (
<button
key={lang}
onClick={() => {
onLanguageChange(lang);
setIsOpen(false);
}}
className={cn(
'w-full flex items-center space-x-3 px-4 py-2.5 text-sm transition-all duration-200',
'hover:bg-banquise-blue/10 focus:bg-banquise-blue/10',
'focus:outline-none',
isSelected
? 'text-banquise-blue-dark font-semibold bg-banquise-blue/10'
: 'text-gray-700 hover:text-banquise-blue-dark'
)}
role="option"
aria-selected={isSelected}
>
<span className="text-lg">{config.flag}</span>
<span className="flex-1 text-left">{config.name}</span>
{isSelected && (
<svg className="w-4 h-4 text-banquise-blue" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
)}
</button>
);
})}
</div>
</>
)}
</div>
);
};