import { useState, useEffect, useId, type CSSProperties } from "react"; import { Link } from "react-router"; import type { LucideIcon } from "lucide-react"; import { Share2, Compass, Library, Globe, BookOpen, Wrench, } from "lucide-react"; import { KIOSK_EVENT, loadWelcome, type WelcomeMessages } from "../kioskStorage"; import { useI18n } from "../i18n"; /** 中 / 英 / 藏 欢迎语(与「语言切换」按钮及轮播同步) */ const WELCOME_MESSAGES = [ { htmlLang: "zh-CN", label: "中文", text: "欢迎来到稻城天文台信息查询", }, { htmlLang: "en", label: "English", text: "Welcome to the Daocheng Observatory Information Query", }, { htmlLang: "bo", label: "བོད་ཡིག", text: "འདབ་ཆུ་གནམ་གཟིགས་ལྟེ་གནས་ཀྱི་ཆ་འཕྲིན་འཚོལ་ཞིབ་ལ་ཕེབས་པར་དགའ་བསུ་ཞུ།", }, ] as const; type MenuItem = { id: string; label: string; icon: LucideIcon; to?: string; href?: string; }; /** * 六块渐变:与品牌 Logo 配色一致(天蓝 / 青柠绿 / 金橙 / 青绿 / 赭红 / 深金琥珀) * 浅→深,对角 bg-gradient-to-br */ const TILE_GRADIENTS = [ "from-[#5DDBFF] via-[#29ABE2] to-[#1680C4]", "from-[#B8E85A] via-[#8DC63F] to-[#5FA028]", "from-[#FFD078] via-[#E8A33D] to-[#C67A18]", "from-[#6EC4B0] via-[#4D9E87] to-[#2F7562]", "from-[#D47868] via-[#A64D3D] to-[#6E3428]", "from-[#F0B84A] via-[#D97E1A] to-[#9A5A10]", ] as const; function ArcMenuTile({ item, index, total, }: { item: MenuItem; index: number; total: number; }) { const Icon = item.icon; const clipUid = useId().replace(/:/g, ""); const gradient = TILE_GRADIENTS[index] ?? TILE_GRADIENTS[TILE_GRADIENTS.length - 1]; const isOuterLeft = index === 0; const isOuterRight = index === total - 1; const isInnerLeftTrap = index === 1; const isInnerRightTrap = index === total - 2; const isOuterEdge = isOuterLeft || isOuterRight; const isInnerTrap = isInnerLeftTrap || isInnerRightTrap; /** 中间两块矩形(第 3、4 入口):去掉底部深色叠层,避免倒影里出现黑色遮罩感 */ const isCenterPair = index === 2 || index === 3; const trapReflectClass = isOuterEdge ? "tile-reflect--trap-outer" : isInnerTrap ? "tile-reflect--trap-inner" : ""; const clipLeftId = `tile-arc-l-${clipUid}`; const clipRightId = `tile-arc-r-${clipUid}`; const clipInnerLId = `tile-arc-il-${clipUid}`; const clipInnerRId = `tile-arc-ir-${clipUid}`; /** * 中间块高 Hc = 宽×4/3。内梯(2、5)短边 0.868·Hi = Hc,长边 0.932·Hi。 * 外梯(1、6)短边 0.82·Ho 与内梯长边对齐 → Ho = Hc×0.932/(0.868×0.82)。 * 第 3、4 块:矩形 aspect 3/4。 */ const faceShellClass = isOuterEdge ? "relative h-[calc(min(40vw,9.5rem)*4/3*0.932/0.868/0.82)] w-[min(38vw,9rem)] overflow-hidden shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:h-[calc(min(36vw,10rem)*4/3*0.932/0.868/0.82)] sm:w-[9.5rem] md:h-[calc(10.25rem*4/3*0.932/0.868/0.82)] md:w-[9.85rem]" : isInnerTrap ? "relative h-[calc(min(40vw,9.5rem)*4/3/0.868)] w-[min(40vw,9.5rem)] overflow-hidden shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:h-[calc(min(36vw,10rem)*4/3/0.868)] sm:w-[min(36vw,10rem)] md:h-[calc(10.25rem*4/3/0.868)] md:w-[10.25rem]" : "relative aspect-[3/4] w-[min(40vw,9.5rem)] overflow-hidden rounded-none shadow-[0_8px_22px_rgba(0,0,0,0.42)] ring-1 ring-white/30 sm:w-[min(36vw,10rem)] md:w-[10.25rem]"; const faceClipStyle: CSSProperties | undefined = isOuterLeft ? { clipPath: `url(#${clipLeftId})` } : isOuterRight ? { clipPath: `url(#${clipRightId})` } : isInnerLeftTrap ? { clipPath: `url(#${clipInnerLId})` } : isInnerRightTrap ? { clipPath: `url(#${clipInnerRId})` } : undefined; const face = ( <> {isOuterLeft ? ( ) : null} {isOuterRight ? ( ) : null} {isInnerLeftTrap ? ( ) : null} {isInnerRightTrap ? ( ) : null}
{!isCenterPair ? (
) : null}
{item.label}
); const wrapped = (
{face}
); if (item.href) { return ( {wrapped} ); } return ( {wrapped} ); } function MenuCarouselArc() { const { t } = useI18n(); const MENU_ITEMS: MenuItem[] = [ { id: "tour", label: t("nav.tour"), icon: Share2, to: "/tour" }, { id: "planetarium", label: t("nav.planetarium"), icon: Compass, to: "/planetarium" }, { id: "wiki", label: t("nav.wiki"), icon: Library, to: "/search" }, { id: "web", label: t("nav.web"), icon: Globe, to: "/web" }, { id: "guide", label: t("nav.guide"), icon: BookOpen, to: "/guide" }, { id: "maintain", label: t("nav.maintain"), icon: Wrench, to: "/admin" }, ]; return (
{/* 手机:两列网格;md+:横向一排(平板/桌面),xl+ 与 index.css 平板段配合 */}
{MENU_ITEMS.map((item, i) => (
))}
); } function defaultWelcomeFromMessages(): WelcomeMessages { return { "zh-CN": WELCOME_MESSAGES[0].text, en: WELCOME_MESSAGES[1].text, bo: WELCOME_MESSAGES[2].text, }; } export function HomePage() { const { lang, setLang } = useI18n(); const [welcomeIdx, setWelcomeIdx] = useState(0); const [welcomeTexts, setWelcomeTexts] = useState(() => loadWelcome(defaultWelcomeFromMessages()) ); const welcomeRows = WELCOME_MESSAGES.map((m) => ({ ...m, text: welcomeTexts[m.htmlLang as keyof WelcomeMessages], })); useEffect(() => { const sync = () => setWelcomeTexts(loadWelcome(defaultWelcomeFromMessages())); window.addEventListener(KIOSK_EVENT, sync); window.addEventListener("storage", sync); return () => { window.removeEventListener(KIOSK_EVENT, sync); window.removeEventListener("storage", sync); }; }, []); useEffect(() => { const i = WELCOME_MESSAGES.findIndex((m) => m.htmlLang === lang); if (i >= 0) setWelcomeIdx(i); }, [lang]); return (
语言
{/* 中央标题区 */}

{welcomeRows[welcomeIdx].text}

{/* 单行弧形 3D 轮播 + 玻璃质感块(参考大屏) */}
); }