lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
125 lines • 8.41 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MorphingNavigation = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const framer_motion_1 = require("framer-motion");
const utils_1 = require("@/components/lib/utils");
const MorphingNavigation = ({ 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] = (0, react_1.useState)(false);
const [isMenuOpen, setIsMenuOpen] = (0, react_1.useState)(false);
const [isMobile, setIsMobile] = (0, react_1.useState)(false);
const navRef = (0, react_1.useRef)(null);
(0, react_1.useEffect)(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const getThemeStyles = (0, react_1.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();
(0, react_1.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, e) => {
e.preventDefault();
setIsMenuOpen(false);
onLinkClick?.(link);
if (enableSmoothTransitions) {
const target = document.querySelector(link.href);
if (target) {
target.scrollIntoView({ behavior: "smooth", block: "start" });
}
}
};
(0, react_1.useEffect)(() => {
const handleClickOutside = (e) => {
if (navRef.current && !navRef.current.contains(e.target) && 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 ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: enablePageBlur && isMenuOpen && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "fixed inset-0 bg-black/20 backdrop-blur-sm z-40", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 } })) }), (0, jsx_runtime_1.jsx)(framer_motion_1.motion.header, { className: (0, utils_1.cn)("fixed top-4 z-50 w-full", className), initial: false, animate: {
top: isMobile ? compactTop : isSticky ? compactTop : initialTop,
}, transition: { duration: animationDuration }, children: (0, jsx_runtime_1.jsxs)(framer_motion_1.motion.nav, { ref: navRef, className: (0, utils_1.cn)("flex justify-center items-center mx-auto backdrop-blur-md border fixed", themeStyles.nav, themeStyles.text, {
"left-1/2 -translate-x-1/2": !isMobile && !isSticky,
"left-0 right-0": isMobile || isSticky,
"sm:w-[70px] sm:h-[70px] sm:rounded-full": isMobile,
}), animate: {
height: isMobile ? 70 : isSticky ? 90 : 100,
width: isMobile ? 70 : isSticky ? 90 : 500,
borderRadius: 9999,
}, transition: { duration: animationDuration }, style: { top: 0, ...customStyles }, children: [(0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: !isMobile && !isSticky &&
links.map((link, i) => ((0, jsx_runtime_1.jsxs)(framer_motion_1.motion.a, { href: link.href, onClick: (e) => 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", children: [link.icon && (0, jsx_runtime_1.jsx)("span", { className: "mr-2 inline-block", children: link.icon }), link.label] }, link.id))) }), (0, jsx_runtime_1.jsx)(framer_motion_1.motion.button, { onClick: handleMenuToggle, className: (0, utils_1.cn)("absolute w-[60px] h-[60px] rounded-full outline-none border cursor-pointer", themeStyles.button, {
hidden: !isSticky && !isMobile,
block: isMobile || isSticky,
}), animate: { scale: isMobile || isSticky ? 1 : 0 }, transition: { delay: isMobile || isSticky ? 0.2 : 0 }, children: customHamburgerIcon || ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center h-full", children: [(0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" }), (0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" }), (0, jsx_runtime_1.jsx)("span", { className: "block w-4 h-0.5 bg-current my-1" })] })) })] }) }), (0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { children: isMenuOpen && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: "fixed inset-0 z-40 flex items-center justify-center", initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.95 }, transition: { duration: 0.3 }, children: (0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { className: (0, utils_1.cn)("p-8 rounded-2xl backdrop-blur-md border w-11/12 max-w-sm", themeStyles.nav, themeStyles.text), style: customStyles, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col space-y-4", children: links.map((link) => ((0, jsx_runtime_1.jsxs)("a", { href: link.href, onClick: (e) => handleLinkClick(link, e), className: "font-bold text-lg tracking-wide lowercase hover:scale-105 transition-transform", children: [link.icon && (0, jsx_runtime_1.jsx)("span", { className: "inline-block mr-3", children: link.icon }), link.label] }, link.id))) }) }) })) })] }));
};
exports.MorphingNavigation = MorphingNavigation;
exports.default = exports.MorphingNavigation;
//# sourceMappingURL=morphing-navigation.js.map