/* eslint-disable @typescript-eslint/no-explicit-any */ 'use client'; import { Cat, Clover, Film, FolderOpen, Globe, Home, Menu, Search, Star, Tv, Users } from 'lucide-react'; import Link from 'next/link'; import { usePathname, useSearchParams } from 'next/navigation'; import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useState, } from 'react'; import { useSite } from './SiteProvider'; import { useWatchRoomContextSafe } from './WatchRoomProvider'; interface SidebarContextType { isCollapsed: boolean; } const SidebarContext = createContext({ isCollapsed: false, }); export const useSidebar = () => useContext(SidebarContext); // 可替换为你自己的 logo 图片 const Logo = () => { const { siteName } = useSite(); return ( {siteName} ); }; interface SidebarProps { onToggle?: (collapsed: boolean) => void; activePath?: string; } // 在浏览器环境下通过全局变量缓存折叠状态,避免组件重新挂载时出现初始值闪烁 declare global { interface Window { __sidebarCollapsed?: boolean; RUNTIME_CONFIG?: { EnableComments?: boolean; RecommendationDataSource?: string; [key: string]: any; }; } } const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => { const pathname = usePathname(); const searchParams = useSearchParams(); const watchRoomContext = useWatchRoomContextSafe(); // 若同一次 SPA 会话中已经读取过折叠状态,则直接复用,避免闪烁 const [isCollapsed, setIsCollapsed] = useState(() => { if ( typeof window !== 'undefined' && typeof window.__sidebarCollapsed === 'boolean' ) { return window.__sidebarCollapsed; } return false; // 默认展开 }); // 首次挂载时读取 localStorage,以便刷新后仍保持上次的折叠状态 useLayoutEffect(() => { const saved = localStorage.getItem('sidebarCollapsed'); if (saved !== null) { const val = JSON.parse(saved); setIsCollapsed(val); window.__sidebarCollapsed = val; } }, []); // 当折叠状态变化时,同步到 data 属性,供首屏 CSS 使用 useLayoutEffect(() => { if (typeof document !== 'undefined') { if (isCollapsed) { document.documentElement.dataset.sidebarCollapsed = 'true'; } else { delete document.documentElement.dataset.sidebarCollapsed; } } }, [isCollapsed]); const [active, setActive] = useState(activePath); useEffect(() => { // 立即根据当前路径更新状态,不等待页面加载 const getCurrentFullPath = () => { const queryString = searchParams.toString(); return queryString ? `${pathname}?${queryString}` : pathname; }; const fullPath = getCurrentFullPath(); setActive(fullPath); }, [pathname, searchParams]); const handleToggle = useCallback(() => { const newState = !isCollapsed; setIsCollapsed(newState); localStorage.setItem('sidebarCollapsed', JSON.stringify(newState)); if (typeof window !== 'undefined') { window.__sidebarCollapsed = newState; } onToggle?.(newState); }, [isCollapsed, onToggle]); const contextValue = { isCollapsed, }; const [menuItems, setMenuItems] = useState([ { icon: Film, label: '电影', href: '/douban?type=movie', }, { icon: Tv, label: '剧集', href: '/douban?type=tv', }, { icon: Cat, label: '动漫', href: '/douban?type=anime', }, { icon: Clover, label: '综艺', href: '/douban?type=show', }, { icon: Tv, label: '电视直播', href: '/live', }, { icon: Globe, label: '网络直播', href: '/web-live', }, ]); useEffect(() => { const runtimeConfig = (window as any).RUNTIME_CONFIG; // 基础菜单项(不包括观影室) const items = [ { icon: Film, label: '电影', href: '/douban?type=movie', }, { icon: Tv, label: '剧集', href: '/douban?type=tv', }, { icon: Cat, label: '动漫', href: '/douban?type=anime', }, { icon: Clover, label: '综艺', href: '/douban?type=show', }, { icon: Tv, label: '电视直播', href: '/live', }, ]; // 如果启用网络直播,添加网络直播入口 if (runtimeConfig?.WEB_LIVE_ENABLED) { items.push({ icon: Globe, label: '网络直播', href: '/web-live', }); } // 如果配置了 OpenList 或 Emby,添加私人影库入口 if (runtimeConfig?.PRIVATE_LIBRARY_ENABLED) { items.push({ icon: FolderOpen, label: '私人影库', href: '/private-library', }); } // 如果启用观影室,添加观影室入口 if (watchRoomContext?.isEnabled) { items.push({ icon: Users, label: '观影室', href: '/watch-room', }); } // 添加自定义分类(如果有) if (runtimeConfig?.CUSTOM_CATEGORIES?.length > 0) { items.push({ icon: Star, label: '自定义', href: '/douban?type=custom', }); } setMenuItems(items); }, [watchRoomContext?.isEnabled]); return ( {/* 在移动端隐藏侧边栏 */}
); }; export default Sidebar;