feat: improved locale selection (made button, use i18n)

This commit is contained in:
Aidan 2025-03-26 23:13:38 -04:00
parent bf4ed43f50
commit e98a80666f
9 changed files with 291 additions and 44 deletions

View file

@ -1,8 +1,9 @@
"use client";
"use client"
import React, { useState } from 'react';
import Link from 'next/link';
import { House, Link as LinkIcon, User, Phone, BookOpen, Music, Rss, X, Menu } from 'lucide-react';
import React, { useState, useRef, useEffect } from 'react'
import Link from 'next/link'
import { House, Link as LinkIcon, User, Phone, BookOpen, Music, Rss, X, Menu, Globe, ChevronDown } from 'lucide-react'
import { useTranslation } from 'react-i18next'
interface NavItemProps {
href: string;
@ -19,6 +20,103 @@ const NavItem = ({ href, icon, children }: NavItemProps) => (
</div>
);
const LanguageSelector = () => {
const { i18n } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const languages = [
{ code: 'en-US', name: 'English' },
];
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 1024);
};
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
setIsOpen(false);
};
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
setIsOpen(false);
}
if (e.key === 'Enter' || e.key === ' ') {
setIsOpen(!isOpen);
}
};
const buttonContent = (
<>
<Globe className="text-md mr-2" strokeWidth={2.5} size={20} />
{languages.find(lang => lang.code === i18n.language)?.name || 'English'}
{!isMobile && (
<ChevronDown className={`w-4 h-4 ml-1 transform transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`} strokeWidth={2.5} size={20} />
)}
</>
);
return (
<div className="relative" ref={dropdownRef}>
<button
onClick={() => setIsOpen(!isOpen)}
onKeyDown={handleKeyDown}
className={`flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all duration-300 ${isMobile ? 'w-full' : ''}`}
aria-expanded={isOpen}
aria-haspopup="true"
>
{buttonContent}
</button>
{isOpen && (
<div
className={`${
isMobile
? 'relative mt-1 w-full bg-gray-800 rounded-md shadow-lg'
: 'absolute right-0 mt-2 w-48 bg-gray-800 rounded-md shadow-lg z-50'
}`}
role="menu"
aria-orientation="vertical"
aria-labelledby="language-menu"
>
{languages.map((lang) => (
<button
key={lang.code}
onClick={() => changeLanguage(lang.code)}
className={`block w-full text-left px-4 py-2 text-sm ${
i18n.language === lang.code
? 'text-white bg-gray-700'
: 'text-gray-300 hover:text-white hover:bg-gray-700'
}`}
role="menuitem"
>
{lang.name}
</button>
))}
</div>
)}
</div>
);
};
export default function Header() {
const [isOpen, setIsOpen] = useState(false);
@ -41,7 +139,13 @@ export default function Header() {
<NavItem href="/manifesto" icon={BookOpen}>Manifesto</NavItem>
<NavItem href="/music" icon={Music}>Music</NavItem>
<NavItem href="https://disfunction.blog" icon={Rss}>Blog</NavItem>
<div className="lg:hidden">
<LanguageSelector />
</div>
</ul>
<div className="hidden lg:block">
<LanguageSelector />
</div>
</nav>
</header>
);