From 2c68fb7e5a3f99ef8dbfe6ece374ea044a482ff3 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 15 Jul 2026 21:46:54 +0200 Subject: [PATCH] Polish admin language dropdown layout and selection styles. Co-authored-by: Cursor --- src/components/language-switcher.tsx | 169 ++++++++++++++++----------- 1 file changed, 102 insertions(+), 67 deletions(-) diff --git a/src/components/language-switcher.tsx b/src/components/language-switcher.tsx index a1f551c4..587df62d 100644 --- a/src/components/language-switcher.tsx +++ b/src/components/language-switcher.tsx @@ -1,6 +1,6 @@ "use client"; -import { Search } from "lucide-react"; +import { Check, ChevronDown, Search } from "lucide-react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { useLocale } from "next-intl"; @@ -43,6 +43,7 @@ export function LanguageSwitcher({ const [open, setOpen] = useState(false); const [search, setSearch] = useState(""); const ref = useRef(null); + const searchRef = useRef(null); const current = LOCALES.find((l) => l.code === locale) ?? LOCALES[0]; const isAdmin = variant === "admin"; @@ -67,11 +68,19 @@ export function LanguageSwitcher({ }, []); useEffect(() => { - if (!open) setSearch(""); + if (!open) { + setSearch(""); + return; + } + const id = window.setTimeout(() => searchRef.current?.focus(), 0); + return () => window.clearTimeout(id); }, [open]); function switchLocale(code: string) { - if (code === locale) return; + if (code === locale) { + setOpen(false); + return; + } startTransition(async () => { await setLocaleCookie(code); router.refresh(); @@ -88,105 +97,131 @@ export function LanguageSwitcher({ aria-label="Change language" title="Language" aria-expanded={open} + aria-haspopup="listbox" className={ isAdmin - ? "flex items-center gap-1.5 h-9 rounded-xl border border-[var(--admin-border)] bg-[var(--admin-surface-elevated)] px-2 text-xs font-bold uppercase tracking-wide text-[var(--admin-text)] hover:bg-[var(--admin-accent)]/15 hover:text-[var(--admin-accent)] transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--admin-accent)] disabled:opacity-60" + ? "flex items-center gap-1.5 h-9 rounded-xl border border-[var(--admin-border)] bg-[var(--admin-surface-elevated)] px-2.5 text-xs font-bold uppercase tracking-wide text-[var(--admin-text)] hover:bg-[var(--admin-accent)]/15 hover:text-[var(--admin-accent)] transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--admin-accent)] disabled:opacity-60" : "nav-item flex items-center gap-1.5 bg-transparent text-[13px] border-none cursor-pointer px-1" } > {current.lang} {current.code.toUpperCase()} - - - + /> {open && (
-
-
+
+
-
+ +
{filtered.length === 0 && ( -

+

No languages found

)} - {filtered.map((l) => ( - - ))} + {filtered.map((l) => { + const selected = l.code === locale; + return ( + + ); + })}
)}