"use client"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { Settings, ExternalLink, Briefcase, Images, Sparkles, Trophy, Building2, Crown, Medal, Award, Edit, LayoutGrid, PlayCircle, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useTheme } from "next-themes"; import { useState, useEffect, useRef } from "react"; import { createPortal } from "react-dom"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { ImageAnnotator } from "@/components/image-annotator"; import { VideoPlayer } from "@/components/video-player"; type RankingItem = { rank: number; userId: string; userName: string; department: string; featuredCount: number; }; type CustomLink = { id: string; name: string; url: string; order: number; toolboxGroup?: number; // 1 或 2 }; type TutorialVideo = { id: string; title: string; videoUrl: string; coverUrl: string | null; description: string | null; order: number; }; type TopNavbarProps = { siteName?: string; siteLogo?: string; siteLogoDark?: string; isAdmin?: boolean; customLinks?: CustomLink[]; toolbox1Name?: string; toolbox1Enabled?: boolean; toolbox2Name?: string; toolbox2Enabled?: boolean; tutorialVideos?: TutorialVideo[]; tutorialEnabled?: boolean; rankingEnabled?: boolean; }; export function TopNavbar({ siteName = "AI Chatbot", siteLogo, siteLogoDark, isAdmin = false, customLinks = [], toolbox1Name = "工具箱", toolbox1Enabled = true, toolbox2Name = "工具箱2", toolbox2Enabled = false, tutorialVideos = [], tutorialEnabled = false, rankingEnabled = true, }: TopNavbarProps) { const router = useRouter(); const { resolvedTheme } = useTheme(); const [mounted, setMounted] = useState(false); const [ranking, setRanking] = useState([]); const [rankingOpen, setRankingOpen] = useState(false); const [tutorialMenuOpen, setTutorialMenuOpen] = useState(false); const [showTutorialModal, setShowTutorialModal] = useState(false); const [currentTutorialVideo, setCurrentTutorialVideo] = useState(null); const [showImageEditor, setShowImageEditor] = useState(false); const [editorImageUrl, setEditorImageUrl] = useState(""); // 移除 fileInputRef,不再需要外部上传 useEffect(() => { setMounted(true); }, []); // 获取精选榜单数据 const fetchRanking = async () => { try { const res = await fetch("/api/featured/ranking"); const data = await res.json(); if (data.ranking) { setRanking(data.ranking); } } catch (error) { console.error("Failed to fetch ranking:", error); } }; // 当下拉菜单打开时获取数据 useEffect(() => { if (rankingOpen) { fetchRanking(); } }, [rankingOpen]); // 获取排名图标 const getRankIcon = (rank: number) => { switch (rank) { case 1: return ; case 2: return ; case 3: return ; default: return {rank}; } }; // 决定显示哪个 LOGO const displayLogo = (siteLogoDark && siteLogoDark.trim() !== "") ? siteLogoDark : siteLogo; // 打开图片编辑器 - 直接打开,不触发上传 const handleOpenImageEditor = () => { setEditorImageUrl(""); // 确保初始为空 setShowImageEditor(true); }; // 处理图片编辑完成 const handleImageEditorConfirm = (annotatedImageUrl: string) => { // 将编辑后的图片存储到 sessionStorage,以便在聊天页面中使用 try { sessionStorage.setItem("pending-edited-image", annotatedImageUrl); } catch (error) { // sessionStorage不可用(如隐私模式),使用URL参数作为备选方案 console.warn("sessionStorage不可用,尝试使用URL参数:", error); // 如果sessionStorage不可用,我们可以将图片数据编码到URL中 // 但由于数据可能很大,这里只记录警告,让用户手动添加图片 // 或者可以显示提示信息 } // 导航到新聊天页面(无论sessionStorage是否成功) router.push("/"); setShowImageEditor(false); setEditorImageUrl(""); }; // 取消图片编辑 const handleImageEditorCancel = () => { setShowImageEditor(false); setEditorImageUrl(""); }; const navContent = ( ); // 使用 Portal 将视频弹窗渲染到 body,确保它在最顶层且不受 nav 的限制 const videoModal = showTutorialModal && currentTutorialVideo && typeof document !== 'undefined' ? createPortal(
{ setShowTutorialModal(false); setCurrentTutorialVideo(null); }} >
e.stopPropagation()} > {/* 标题栏 - 包含标题和关闭按钮 */}
{/* 占位符保持标题居中 */}

{currentTutorialVideo.title}

{/* 视频播放器 */} {currentTutorialVideo.videoUrl.includes('youtube.com') || currentTutorialVideo.videoUrl.includes('youtu.be') ? (