import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { Check, Globe } from "lucide-react"; import { LANGUAGES, type LangCode } from "../i18n"; // Compact language picker (globe + current code). Presentational: the parent decides what // changing the language does (set it; persist server-side when signed in). // // Two variants: "header" (legacy inline dropdown, opens below) and "rail" (used in the left // nav's bottom icon cluster — an icon-only button whose menu is portaled to and // anchored to the right + above the button, escaping the nav's backdrop-filter which would // otherwise trap an absolutely-positioned popover). export default function LanguageSwitcher({ value, onChange, align = "right", variant = "header", }: { value: LangCode; onChange: (code: LangCode) => void; align?: "left" | "right"; variant?: "header" | "rail"; }) { const [open, setOpen] = useState(false); const closeTimer = useRef | null>(null); const btnRef = useRef(null); const panelRef = useRef(null); const [pos, setPos] = useState<{ left: number; bottom: number }>({ left: 0, bottom: 0 }); const current = LANGUAGES.find((l) => l.code === value) ?? LANGUAGES[0]; function openNow() { if (closeTimer.current) clearTimeout(closeTimer.current); setOpen(true); } function closeSoon() { closeTimer.current = setTimeout(() => setOpen(false), 200); } function toggleRail() { if (!open) { const r = btnRef.current?.getBoundingClientRect(); if (r) setPos({ left: r.right + 8, bottom: window.innerHeight - r.bottom }); } setOpen((o) => !o); } // Rail popover: dismiss on outside click / Escape (it's portaled, so a contains() check // spans both the button and the floating panel). useEffect(() => { if (variant !== "rail" || !open) return; function onDoc(e: MouseEvent) { const target = e.target as Node; if (panelRef.current?.contains(target) || btnRef.current?.contains(target)) return; setOpen(false); } function onKey(e: KeyboardEvent) { if (e.key === "Escape") setOpen(false); } document.addEventListener("mousedown", onDoc); document.addEventListener("keydown", onKey); return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); }; }, [variant, open]); const menu = (
{LANGUAGES.map((l) => ( ))}
); if (variant === "rail") { return ( <> {open && createPortal(
{menu}
, document.body )} ); } return (
{open && (
{LANGUAGES.map((l) => ( ))}
)}
); }