diff --git a/src/components/language-switcher.tsx b/src/components/language-switcher.tsx index ef9b272..6bd60d8 100644 --- a/src/components/language-switcher.tsx +++ b/src/components/language-switcher.tsx @@ -3,9 +3,10 @@ import "@/i18n"; import { ChevronDown, Globe } from "lucide-react"; -import { useEffect, useMemo, useRef, useState, type ReactNode } from "react"; +import { useMemo, useState, type ReactNode } from "react"; import { useTranslation } from "react-i18next"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { normalizeLanguage, SUPPORTED_LANGUAGES, type AppLanguage } from "@/i18n"; import { cn } from "@/lib/utils"; @@ -28,7 +29,6 @@ export function LanguageSwitcher({ const { i18n, t } = useTranslation("common"); const active = normalizeLanguage(i18n.language) as AppLanguage; const [isOpen, setIsOpen] = useState(false); - const containerRef = useRef(null); const options = useMemo( () => @@ -40,22 +40,6 @@ export function LanguageSwitcher({ [t], ); - useEffect(() => { - function handleClickOutside(event: MouseEvent): void { - if (containerRef.current && !containerRef.current.contains(event.target as Node)) { - setIsOpen(false); - } - } - - if (isOpen) { - document.addEventListener("mousedown", handleClickOutside); - } - - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [isOpen]); - async function handleSelect(code: AppLanguage): Promise { await i18n.changeLanguage(code); setIsOpen(false); @@ -91,72 +75,74 @@ export function LanguageSwitcher({ menuAlign ?? (variant === "header" || variant === "default" ? "start" : "end"); return ( -
- + } + /> + - - {showFlag && currentFlag ? {currentFlag} : null} - {showLabel ? {currentLabel} : null} - - - - {isOpen ? ( -
-
- {options.map((option) => ( - - ))} -
+
+ {options.map((option) => ( + + ))}
- ) : null} -
+
+ ); } @@ -166,6 +152,11 @@ export function LanguageSwitcherMinimal({ className?: string; }): ReactNode { return ( - + ); } diff --git a/src/components/layout/player-panel.tsx b/src/components/layout/player-panel.tsx index 1998b2e..61e657f 100644 --- a/src/components/layout/player-panel.tsx +++ b/src/components/layout/player-panel.tsx @@ -44,7 +44,12 @@ export function PlayerPanel({ className, )} > -
+
-
-
+
+
(null); const [loading, setLoading] = useState(true); @@ -17,9 +18,9 @@ export function PlayRulesScreen() { async function loadRules() { try { const res = await getPublicSettings("frontend"); - const ruleItem = res.items.find((item) => item.key === "frontend.play_rules_html"); - if (ruleItem && typeof ruleItem.value === "string" && ruleItem.value.trim() !== "") { - setHtmlContent(ruleItem.value); + const html = resolvePlayRulesHtml(res.items, i18n.language); + if (html) { + setHtmlContent(html); } else { setHtmlContent(`
${t("rules.empty", { defaultValue: "暂无玩法规则说明" })}
`); } @@ -30,7 +31,7 @@ export function PlayRulesScreen() { } } void loadRules(); - }, [t]); + }, [i18n.language, t]); return ( [item.key, item.value])); + const legacy = asNonEmptyString(kv.get(KEY_LEGACY)); + const zh = asNonEmptyString(kv.get(KEY_ZH)); + const en = asNonEmptyString(kv.get(KEY_EN)); + const ne = asNonEmptyString(kv.get(KEY_NE)); + + const lang: AppLanguage = normalizeLanguage(language); + + if (lang === "zh") { + return zh ?? legacy; + } + if (lang === "ne") { + return ne ?? en ?? zh ?? legacy; + } + return en ?? zh ?? legacy; +}