From b7a117d58c514f36ca2c6421a355cf491679c31e Mon Sep 17 00:00:00 2001 From: Vaibhav Tripathi Date: Sat, 31 May 2025 14:50:18 +0530 Subject: [PATCH 1/2] GFG | refactor: updated navbar --- components/ui/FloatingNavbar.tsx | 171 ++++++++++++++++++++++++++----- 1 file changed, 147 insertions(+), 24 deletions(-) diff --git a/components/ui/FloatingNavbar.tsx b/components/ui/FloatingNavbar.tsx index 4abb6e4..acb4303 100644 --- a/components/ui/FloatingNavbar.tsx +++ b/components/ui/FloatingNavbar.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { useState } from "react"; +import React, { use, useState } from "react"; import { motion, AnimatePresence, @@ -8,8 +8,9 @@ import { } from "framer-motion"; import Link from "next/link"; import { cn } from "@/lib/utils"; +import Image from "next/image"; +import { usePathname } from "next/navigation"; -// Accept props correctly (function parameter was broken) interface NavItem { name: string; link: string; @@ -23,54 +24,176 @@ interface Props { const FloatingNavbar: React.FC = ({ navItems, className }) => { const { scrollYProgress } = useScroll(); + + // set true for the initial state so that nav bar is visible in the hero section const [visible, setVisible] = useState(true); + const [isScrolled, setIsScrolled] = useState(false); useMotionValueEvent(scrollYProgress, "change", (current) => { + // Check if current is not undefined and is a number if (typeof current === "number") { - const previous = scrollYProgress.getPrevious(); - const direction = current - (previous ?? 0); + let direction = current! - scrollYProgress.getPrevious()!; if (scrollYProgress.get() < 0.05) { + // also set true for the initial state setVisible(true); + setIsScrolled(false); } else { - setVisible(direction < 0); + if (direction < 0) { + setVisible(true); + } + setIsScrolled(true); } } }); + const pathname = usePathname(); + const isDashboard = pathname?.startsWith("/dashboard"); + const isAdminDashboard = pathname === "/dashboard/admin"; return ( - {navItems.map((navItem, idx) => ( - - {navItem.icon} - {navItem.name} - - ))} + {/* Elixir text on the left */} + + Elixir Logo + Elixir + + + {/* Navigation items in the center */} + + {navItems.map((navItem: any, idx: number) => ( + + + {navItem.icon} + {navItem.name} + + + ))} + + + {/* Login button on the right */} + +
+ {!isDashboard ? ( + + Login + + ) : isAdminDashboard ? ( +
+ Admin +
+ ) : ( +
+ User +
+ )} +
+ + +
); }; - -export default FloatingNavbar; +export default FloatingNavbar; \ No newline at end of file From ef7530bbc46c2182c3a40816d2696075a60ceb65 Mon Sep 17 00:00:00 2001 From: Vaibhav Tripathi Date: Sat, 31 May 2025 16:55:44 +0530 Subject: [PATCH 2/2] GFG | refactor: updated navbar for smaller screen --- components/ui/FloatingNavbar.tsx | 279 +++++++++++++++++-------------- components/ui/MobileNavModal.tsx | 148 ++++++++++++++++ 2 files changed, 299 insertions(+), 128 deletions(-) create mode 100644 components/ui/MobileNavModal.tsx diff --git a/components/ui/FloatingNavbar.tsx b/components/ui/FloatingNavbar.tsx index acb4303..660ecde 100644 --- a/components/ui/FloatingNavbar.tsx +++ b/components/ui/FloatingNavbar.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { use, useState } from "react"; +import React, { useState } from "react"; import { motion, AnimatePresence, @@ -10,6 +10,8 @@ import Link from "next/link"; import { cn } from "@/lib/utils"; import Image from "next/image"; import { usePathname } from "next/navigation"; +import MobileNavModal from "./MobileNavModal"; +import { HiMenu } from "react-icons/hi"; interface NavItem { name: string; @@ -28,6 +30,7 @@ const FloatingNavbar: React.FC = ({ navItems, className }) => { // set true for the initial state so that nav bar is visible in the hero section const [visible, setVisible] = useState(true); const [isScrolled, setIsScrolled] = useState(false); + const [mobileNavOpen, setMobileNavOpen] = useState(false); useMotionValueEvent(scrollYProgress, "change", (current) => { // Check if current is not undefined and is a number @@ -51,149 +54,169 @@ const FloatingNavbar: React.FC = ({ navItems, className }) => { const isAdminDashboard = pathname === "/dashboard/admin"; return ( - - - {/* Elixir text on the left */} - - Elixir Logo - Elixir - - - {/* Navigation items in the center */} + <> + - {navItems.map((navItem: any, idx: number) => ( - - - {navItem.icon} - {navItem.name} - - - ))} - - - {/* Login button on the right */} - -
- {!isDashboard ? ( - - Login - - ) : isAdminDashboard ? ( -
- Admin -
- ) : ( -
- User -
+ {/* Elixir text on the left */} + + Elixir Logo + Elixir + + {/* Hamburger icon for mobile */} +
+
- - - - - + > + {navItems.map((navItem: any, idx: number) => ( + + + {navItem.icon} + + {navItem.name} + + + + ))} + + {/* Login button on the right (hidden on mobile) */} + +
+ {!isDashboard ? ( + <> + + Login + + + ) : isAdminDashboard ? ( +
+ Admin +
+ ) : ( +
+ User +
+ )} +
+ + +
+ + + {/* Mobile Navigation Modal */} + setMobileNavOpen(false)} + navItems={navItems} + /> + ); }; -export default FloatingNavbar; \ No newline at end of file +export default FloatingNavbar; diff --git a/components/ui/MobileNavModal.tsx b/components/ui/MobileNavModal.tsx new file mode 100644 index 0000000..3e9fdaf --- /dev/null +++ b/components/ui/MobileNavModal.tsx @@ -0,0 +1,148 @@ +import React from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { cn } from "@/lib/utils"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import Image from "next/image"; +import { HiX, HiArrowRight } from "react-icons/hi"; + +interface NavItem { + name: string; + link: string; + icon?: JSX.Element; +} + +interface MobileNavModalProps { + open: boolean; + onClose: () => void; + navItems: NavItem[]; +} + +const overlayVariants = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, +}; + +const modalVariants = { + hidden: { y: "100%", opacity: 0 }, + visible: { y: 0, opacity: 1 }, +}; + +const MobileNavModal: React.FC = ({ + open, + onClose, + navItems, +}) => { + const pathname = usePathname(); + const isDashboard = pathname?.startsWith("/dashboard"); + const isAdminDashboard = pathname === "/dashboard/admin"; + + return ( + + {open && ( + <> + {/* Overlay */} + + {/* Modal */} + + {/* Logo/brand and close button row */} +
+
+ Elixir Logo + + Elixir + +
+ +
+ {/* Nav items */} + + {/* Login/Dashboard button */} +
+ {!isDashboard ? ( + + Login + + {/* Blue highlight at the bottom center */} + + + ) : isAdminDashboard ? ( +
+ Admin + +
+ ) : ( +
+ User + +
+ )} +
+
+ + )} +
+ ); +}; + +export default MobileNavModal;