"use client"; import React, { useEffect, useRef, useState, useCallback } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { cn } from "../../lib/utils"; export interface MorphingNavigationLink { id: string; label: string; href: string; icon?: React.ReactNode; } export interface MorphingNavigationProps { links: MorphingNavigationLink[]; scrollThreshold?: number; enablePageBlur?: boolean; theme?: "dark" | "light" | "glass" | "custom"; backgroundColor?: string; textColor?: string; borderColor?: string; initialTop?: number; compactTop?: number; animationDuration?: number; className?: string; onLinkClick?: (link: MorphingNavigationLink) => void; onMenuToggle?: (isOpen: boolean) => void; enableSmoothTransitions?: boolean; customHamburgerIcon?: React.ReactNode; disableAutoMorph?: boolean; } export const MorphingNavigation: React.FC = ({ links, scrollThreshold = 100, enablePageBlur = true, theme = "glass", backgroundColor, textColor, borderColor, initialTop = 70, compactTop = 20, animationDuration = 1, className, onLinkClick, onMenuToggle, enableSmoothTransitions = true, customHamburgerIcon, disableAutoMorph = false, }) => { const [isSticky, setIsSticky] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); const [isMobile, setIsMobile] = useState(false); const navRef = useRef(null); useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 768); }; handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); const getThemeStyles = useCallback(() => { switch (theme) { case "dark": return { nav: "bg-black/80 border-gray-800", text: "text-white", button: "bg-black/50 border-gray-700", }; case "light": return { nav: "bg-white/80 border-gray-200", text: "text-gray-900", button: "bg-white/50 border-gray-300", }; case "custom": return { nav: backgroundColor ? "" : "bg-white/5 border-white/10", text: textColor ? "" : "text-white", button: "bg-black/30 border-white/10", }; case "glass": default: return { nav: "bg-white/5 border-white/10", text: "text-foreground", button: "bg-black/30 border-white/10", }; } }, [theme, backgroundColor, textColor]); const themeStyles = getThemeStyles(); useEffect(() => { if (disableAutoMorph && !isMobile) return; const handleScroll = () => { if (isMobile) { setIsSticky(true); setIsMenuOpen(false); } else { setIsSticky(window.scrollY >= scrollThreshold); setIsMenuOpen(false); } }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, [scrollThreshold, disableAutoMorph, isMobile]); const handleMenuToggle = () => { const open = !isMenuOpen; setIsMenuOpen(open); if (isMobile && open) { setIsSticky(true); } else if (isMobile && !open) { setIsSticky(window.scrollY >= scrollThreshold); } else { setIsSticky(false); } onMenuToggle?.(open); }; const handleLinkClick = (link: MorphingNavigationLink, e: React.MouseEvent) => { e.preventDefault(); setIsMenuOpen(false); onLinkClick?.(link); if (enableSmoothTransitions) { const target = document.querySelector(link.href); if (target) { target.scrollIntoView({ behavior: "smooth", block: "start" }); } } }; useEffect(() => { const handleClickOutside = (e: MouseEvent) => { if (navRef.current && !navRef.current.contains(e.target as Node) && isMenuOpen) { setIsMenuOpen(false); } }; document.addEventListener("click", handleClickOutside); return () => document.removeEventListener("click", handleClickOutside); }, [isMenuOpen]); const customStyles = { backgroundColor: theme === "custom" ? backgroundColor : undefined, color: theme === "custom" ? textColor : undefined, borderColor: theme === "custom" ? borderColor : undefined, }; return ( <> {enablePageBlur && isMenuOpen && ( )} {!isMobile && !isSticky && links.map((link, i) => ( handleLinkClick(link, e)} initial={{ opacity: 0, scale: 0.5 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0 }} transition={{ delay: i * 0.1 }} className="px-5 py-2.5 text-sm font-bold lowercase tracking-wide" > {link.icon && {link.icon}} {link.label} ))} {customHamburgerIcon || (
)}
{isMenuOpen && ( )} ); }; export default MorphingNavigation;