import { useState, useEffect } from "react"; import { Outlet, Link, useLocation } from "react-router"; import type { LucideIcon } from "lucide-react"; import { Menu, Home, Mountain, Star, Share2, Compass, Library, Globe, BookOpen, Wrench, } from "lucide-react"; import { TibetanPattern } from "./TibetanPattern"; import { fetchAndApplyKioskBundle } from "../api/kioskApi"; import { DEFAULT_HOME_BG_URLS, KIOSK_EVENT, loadHomeBackgrounds } from "../kioskStorage"; const BG_ROTATE_MS = 7000; function preloadImages(urls: readonly string[]) { urls.forEach((src) => { const img = new Image(); img.src = src; }); } export function Layout() { const [sidebarOpen, setSidebarOpen] = useState(false); const [homeBgIndex, setHomeBgIndex] = useState(0); const [homeBackgrounds, setHomeBackgrounds] = useState(loadHomeBackgrounds); const location = useLocation(); const isHome = location.pathname === "/"; const isTourPage = location.pathname === "/tour"; const isSearchPage = location.pathname === "/search"; const isGuidePage = location.pathname === "/guide"; const isAdminPage = location.pathname === "/admin"; const isViewportLockPage = isTourPage || isSearchPage || isGuidePage; /** 顶栏品牌标题全站统一(非首页顶栏显示) */ const headerBrandTitle = "稻城天文台信息查询"; useEffect(() => { const sync = () => { setHomeBackgrounds(loadHomeBackgrounds()); }; window.addEventListener(KIOSK_EVENT, sync); window.addEventListener("storage", sync); return () => { window.removeEventListener(KIOSK_EVENT, sync); window.removeEventListener("storage", sync); }; }, []); /** 启动时从后端拉取展台 bundle,写入 localStorage 并触发 KIOSK_EVENT(后端不可用时静默使用本地/默认) */ useEffect(() => { let cancelled = false; void (async () => { try { await fetchAndApplyKioskBundle(); } catch (e) { if (!cancelled) { console.warn("[kiosk] 无法从后端拉取 bundle(将使用本地/默认数据)", e); } } })(); return () => { cancelled = true; }; }, []); useEffect(() => { preloadImages(homeBackgrounds); }, [homeBackgrounds]); useEffect(() => { setHomeBgIndex((i) => homeBackgrounds.length === 0 ? 0 : Math.min(i, homeBackgrounds.length - 1) ); }, [homeBackgrounds.length]); useEffect(() => { if (!isHome) return; const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); if (reduceMotion.matches) return; const n = homeBackgrounds.length; if (n <= 1) return; const interval = window.setInterval(() => { setHomeBgIndex((prev) => (prev + 1) % n); }, BG_ROTATE_MS); return () => window.clearInterval(interval); }, [isHome, homeBackgrounds.length]); useEffect(() => { const root = document.documentElement; if (isViewportLockPage) { root.classList.add("app-viewport-lock"); } else { root.classList.remove("app-viewport-lock"); } return () => root.classList.remove("app-viewport-lock"); }, [isViewportLockPage]); /** 与首页六块入口顺序、文案一致;首页不含「首页」项,顶栏保留首页便于返回 */ const navItems: ( | { id: string; path: string; label: string; icon: LucideIcon } | { id: string; href: string; label: string; icon: LucideIcon; external: true } )[] = [ { id: "home", path: "/", label: "首页", icon: Home }, { id: "tour", path: "/tour", label: "共享天文台", icon: Share2 }, { id: "planetarium", path: "/planetarium", label: "天文馆导览", icon: Compass }, { id: "wiki", path: "/search", label: "天文知识库", icon: Library }, { id: "web", href: "https://www.cas.cn/", label: "天文馆官网", icon: Globe, external: true, }, { id: "guide", path: "/guide", label: "操作指南", icon: BookOpen }, { id: "maintain", path: "/admin", label: "系统维护", icon: Wrench }, ]; return (