'use client'; import { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; import { useRouter, usePathname } from 'next/navigation'; import { Bars3Icon, XMarkIcon, UserCircleIcon } from '@heroicons/react/24/outline'; import { motion, AnimatePresence, useScroll, useTransform, useSpring } from 'framer-motion'; import { useAuth } from '@/contexts/AuthContext'; export default function Navbar() { const [isOpen, setIsOpen] = useState(false); const [isHidden, setIsHidden] = useState(false); const [isScrolled, setIsScrolled] = useState(false); const [showScrollTop, setShowScrollTop] = useState(false); const [navbarHeight, setNavbarHeight] = useState(0); const [scrollProgress, setScrollProgress] = useState(0); const navbarRef = useRef(null); const { user, isAuthenticated, logout } = useAuth(); const router = useRouter(); const pathname = usePathname(); const { scrollY } = useScroll(); // 弹簧动画效果 const springConfig = { stiffness: 300, damping: 30 }; const navbarY = useSpring(useTransform(scrollY, [0, 100], [0, -100]), springConfig); const navbarOpacity = useSpring(useTransform(scrollY, [0, 50], [1, 0.95]), springConfig); const scrollProgressSpring = useSpring(scrollProgress, springConfig); // 在auth页面隐藏navbar const isAuthPage = pathname === '/auth'; // 检测navbar高度并设置CSS自定义属性 useEffect(() => { const updateHeight = () => { if (navbarRef.current) { const height = navbarRef.current.offsetHeight; setNavbarHeight(height); document.documentElement.style.setProperty('--navbar-height', `${height}px`); } }; updateHeight(); window.addEventListener('resize', updateHeight); return () => window.removeEventListener('resize', updateHeight); }, []); // 滚动进度计算 useEffect(() => { const handleScroll = () => { const scrollTop = window.scrollY; const docHeight = document.documentElement.scrollHeight - window.innerHeight; const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0; setScrollProgress(progress); }; window.addEventListener('scroll', handleScroll, { passive: true }); return () => window.removeEventListener('scroll', handleScroll); }, []); useEffect(() => { let lastScrollY = 0; let ticking = false; const handleScroll = () => { if (!ticking) { window.requestAnimationFrame(() => { const currentScrollY = window.scrollY; // 检测是否滚动到顶部 setIsScrolled(currentScrollY > 20); // 显示返回顶部按钮(滚动超过300px) setShowScrollTop(currentScrollY > 300); // 更敏感的隐藏逻辑:只要往下滚动就隐藏,不管滚动多少 if (!isAuthPage && currentScrollY > lastScrollY && currentScrollY > 10) { setIsHidden(true); } else if (currentScrollY < lastScrollY) { // 往上滚动就显示 setIsHidden(false); } lastScrollY = currentScrollY; ticking = false; }); ticking = true; } }; if (!isAuthPage) { window.addEventListener('scroll', handleScroll, { passive: true }); } return () => window.removeEventListener('scroll', handleScroll); }, [isAuthPage]); const handleLogout = () => { logout(); router.push('/'); setIsOpen(false); }; const handleLinkClick = () => { setIsOpen(false); }; // 在auth页面不渲染navbar if (isAuthPage) { return null; } const scrollToTop = () => { window.scrollTo({ top: 0, behavior: 'smooth', }); }; const navItems = [ { href: '/', label: '首页', icon: null }, { href: '/skins', label: '皮肤库', icon: null }, ]; return ( <> {/* 滚动进度条 */}
{/* Logo */} C CarrotSkin {/* Desktop Navigation */}
{navItems.map((item, index) => ( {item.label} {pathname === item.href && ( )} ))} {/* 用户头像框 - 增强的微交互 */} {isAuthenticated ? (
{user?.avatar ? ( {user.username} ) : ( )} {user?.username} 退出登录
) : ( 登录 )}
{/* Mobile menu button */}
setIsOpen(!isOpen)} className="text-gray-700 dark:text-gray-300 hover:text-orange-500 dark:hover:text-orange-400 transition-colors duration-200 p-2" whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} animate={{ rotate: isOpen ? 180 : 0 }} transition={{ duration: 0.3 }} > {isOpen ? ( ) : ( )}
{/* Mobile Navigation */} {isOpen && (
{navItems.map((item, index) => ( {item.label} ))} {isAuthenticated ? ( <>
{user?.avatar ? ( {user.username} ) : ( )} {user?.username}
) : ( <> 登录 注册 )}
)}
{/* 返回顶部按钮 */} {showScrollTop && ( )} ); }