From 2bf44e4c291a2151a4eb08254fe0243f148059a7 Mon Sep 17 00:00:00 2001 From: kang Date: Fri, 22 May 2026 16:55:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E4=B8=8B=E6=8B=89=E4=BA=A4=E4=BA=92=E5=B9=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=8E=A9=E6=B3=95=E8=A7=84=E5=88=99=E5=A4=9A?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/language-switcher.tsx | 153 +++++++++++------------ src/components/layout/player-panel.tsx | 8 +- src/features/hall/hall-screen.tsx | 5 +- src/features/rules/play-rules-screen.tsx | 11 +- src/lib/play-rules-html.ts | 38 ++++++ 5 files changed, 126 insertions(+), 89 deletions(-) create mode 100644 src/lib/play-rules-html.ts 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; +}