Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69f244b219 | ||
|
|
061add06aa | ||
|
|
5b4c24e737 |
@@ -11,6 +11,7 @@ const LanguageSwitcher = () => {
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isMobile, setIsMobile] = useState(false);
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
|
const [focusedIndex, setFocusedIndex] = useState<number>(-1);
|
||||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const languages = [
|
const languages = [
|
||||||
@@ -30,8 +31,28 @@ const LanguageSwitcher = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
if (e.key === 'Escape') {
|
if (!isOpen) return;
|
||||||
setIsOpen(false);
|
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Escape':
|
||||||
|
setIsOpen(false);
|
||||||
|
setFocusedIndex(-1);
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
e.preventDefault();
|
||||||
|
setFocusedIndex(prev => (prev + 1) % languages.length);
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
e.preventDefault();
|
||||||
|
setFocusedIndex(prev => (prev - 1 + languages.length) % languages.length);
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
e.preventDefault();
|
||||||
|
if (focusedIndex >= 0) {
|
||||||
|
handleLanguageChange(languages[focusedIndex].code);
|
||||||
|
setFocusedIndex(-1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,7 +84,10 @@ const LanguageSwitcher = () => {
|
|||||||
px-4 py-2 rounded-full transition-all duration-200
|
px-4 py-2 rounded-full transition-all duration-200
|
||||||
hover:bg-zinc-800/50 border border-transparent hover:border-zinc-800
|
hover:bg-zinc-800/50 border border-transparent hover:border-zinc-800
|
||||||
hover:scale-105 active:scale-95"
|
hover:scale-105 active:scale-95"
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={() => {
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
setFocusedIndex(-1);
|
||||||
|
}}
|
||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
aria-label="Select language"
|
aria-label="Select language"
|
||||||
@@ -79,18 +103,21 @@ const LanguageSwitcher = () => {
|
|||||||
${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none'}`}
|
${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none'}`}
|
||||||
role="listbox"
|
role="listbox"
|
||||||
aria-label="Languages"
|
aria-label="Languages"
|
||||||
|
aria-activedescendant={focusedIndex >= 0 ? `lang-option-${languages[focusedIndex].code}` : undefined}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
{languages.map((lang) => (
|
{languages.map((lang, index) => (
|
||||||
<button
|
<button
|
||||||
key={lang.code}
|
key={lang.code}
|
||||||
|
id={`lang-option-${lang.code}`}
|
||||||
className={`w-full text-left px-4 py-2 text-sm transition-colors duration-200
|
className={`w-full text-left px-4 py-2 text-sm transition-colors duration-200
|
||||||
hover:bg-zinc-800/50
|
hover:bg-zinc-800/50
|
||||||
${locale === lang.code
|
${locale === lang.code
|
||||||
? 'bg-zinc-800 text-white'
|
? 'bg-zinc-800 text-white'
|
||||||
: 'text-zinc-400 hover:text-white'
|
: 'text-zinc-400 hover:text-white'
|
||||||
}`}
|
}
|
||||||
|
${focusedIndex === index ? 'ring-2 ring-orange-500 ring-inset' : ''}`}
|
||||||
onClick={() => handleLanguageChange(lang.code)}
|
onClick={() => handleLanguageChange(lang.code)}
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={locale === lang.code}
|
aria-selected={locale === lang.code}
|
||||||
|
|||||||
Reference in New Issue
Block a user