"use client"; import { useState, useRef, useEffect } from "react"; import { useLocale, useTranslations } from "next-intl"; import { useRouter, usePathname } from "@/i18n/navigation"; import { Cog6ToothIcon, ChevronDownIcon } from "@heroicons/react/24/outline"; import { useTheme } from "./theme/ThemeProvider"; import { SUPPORTED_LOCALES, getLocaleConfig } from "@/lib/locales"; import { ACCENT_COLORS, COLOR_SCHEMES, type AccentColor, type ColorScheme, } from "@/types/theme"; /** * Unified preferences dropdown with accordion sections. * * Replaces the standalone LanguageSwitcher and floating ThemeSelector * with a single "Start Menu"-style panel in the header. * * Sections: * - Language (locale picker) * - Theme (color scheme + accent color) */ export default function PreferencesMenu() { const t = useTranslations(); const locale = useLocale(); const router = useRouter(); const pathname = usePathname(); const { theme, setAccentColor, setColorScheme, systemPrefersDark } = useTheme(); const [isOpen, setIsOpen] = useState(false); const [openSection, setOpenSection] = useState(null); const menuRef = useRef(null); // Close dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { setIsOpen(false); } } document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); // Close on Escape useEffect(() => { if (!isOpen) return; function handleEscape(event: KeyboardEvent) { if (event.key === "Escape") setIsOpen(false); } document.addEventListener("keydown", handleEscape); return () => document.removeEventListener("keydown", handleEscape); }, [isOpen]); const toggleSection = (section: string) => { setOpenSection((prev) => (prev === section ? null : section)); }; const handleLanguageChange = (newLocale: string) => { router.replace(pathname, { locale: newLocale }); setIsOpen(false); }; // Find the current locale config for the trigger badge const currentLocale = getLocaleConfig(locale); return (
{/* Trigger button */} {/* Dropdown panel */} {isOpen && (
{/* ── Language section ─────────────────────────────────── */}
{openSection === "language" && (
{SUPPORTED_LOCALES.map((lang) => { const isSelected = lang.code === locale; return ( ); })}
)}
{/* ── Theme section ────────────────────────────────────── */}
{openSection === "theme" && (
{/* Appearance (color scheme) */}
{t("Theme.appearance")}
{Object.entries(COLOR_SCHEMES).map(([key, info]) => { const scheme = key as ColorScheme; const isSelected = theme.colorScheme === scheme; return ( ); })}
{/* Accent color */}
{t("Theme.accentColor")}
{Object.entries(ACCENT_COLORS).map(([key, info]) => { const color = key as AccentColor; const isSelected = theme.accent === color; return ( ); })}
)}
)}
); }