diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json index 88e1fc4a..cd9c8c1e 100644 --- a/Frontend/package-lock.json +++ b/Frontend/package-lock.json @@ -23,8 +23,8 @@ "gsap": "^3.13.0", "jwt-decode": "^4.0.0", "lucide-react": "^0.545.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-dropzone": "^14.3.8", "react-helmet-async": "^2.0.5", "react-hot-toast": "^2.6.0", @@ -4204,24 +4204,28 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^18.3.1" } }, "node_modules/react-dropzone": { @@ -4620,10 +4624,13 @@ } }, "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/seedrandom": { "version": "3.0.5", diff --git a/Frontend/package.json b/Frontend/package.json index 66dab3c7..4dbfe129 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -32,8 +32,8 @@ "gsap": "^3.13.0", "jwt-decode": "^4.0.0", "lucide-react": "^0.545.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-dropzone": "^14.3.8", "react-helmet-async": "^2.0.5", "react-hot-toast": "^2.6.0", diff --git a/Frontend/src/components/Navbar.jsx b/Frontend/src/components/Navbar.jsx index 590bf48e..0094da05 100644 --- a/Frontend/src/components/Navbar.jsx +++ b/Frontend/src/components/Navbar.jsx @@ -1,191 +1,289 @@ -import { useState, useEffect } from "react"; -import { Link, useNavigate, useLocation } from "react-router-dom"; +import { useEffect, useMemo, useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; -import { Menu, X, Home } from "lucide-react"; +import { Menu, X } from "lucide-react"; import ThemeToggle from "./ThemeToggle"; -export default function Navbar() { - const navigate = useNavigate(); - const location = useLocation(); - const { token } = useSelector((state) => state.auth); - const [mobileMenuOpen, setMobileMenuOpen] = useState(false); - const [activeSection, setActiveSection] = useState(""); +const NAV_TONES = { + landing: { + nav: "fixed top-6 left-1/2 -translate-x-1/2 w-[95%] max-w-7xl bg-black/10 backdrop-blur-xl rounded-full border border-white/20 z-50 text-skin-primary", + link: "text-gray-200 hover:text-emerald-400", + mobileMenu: "bg-white backdrop-blur-md rounded-2xl shadow-xl border border-gray-200", + mobileLink: "text-gray-600 hover:text-gray-900", + menuButton: "text-gray-900 hover:bg-gray-100", + logoPrimary: "text-white-800", + logoSecondary: "text-emerald-500", + activeLink: "text-emerald-400", + activeMobile: "text-emerald-500 bg-emerald-50", + }, + skin: { + nav: "fixed top-6 left-1/2 transform -translate-x-1/2 w-[95%] max-w-7xl bg-skin-primary/95 backdrop-blur-md rounded-full shadow-lg z-50 border border-skin-primary", + link: "text-gray-600 hover:text-skin-primary", + mobileMenu: "bg-white backdrop-blur-md rounded-2xl shadow-xl border border-gray-200", + mobileLink: "text-gray-600 hover:text-skin-primary", + menuButton: "text-skin-primary hover:bg-gray-100", + logoPrimary: "text-skin-primary", + logoSecondary: "text-emerald-500", + activeLink: "text-emerald-500", + activeMobile: "text-emerald-500 bg-emerald-50", + }, + light: { + nav: "fixed top-6 left-1/2 transform -translate-x-1/2 w-[95%] max-w-7xl bg-white/95 backdrop-blur-md rounded-full shadow-lg z-50 border border-gray-200", + link: "text-gray-600 hover:text-gray-900", + mobileMenu: "bg-white backdrop-blur-md rounded-2xl shadow-xl border border-gray-200", + mobileLink: "text-gray-600 hover:text-gray-900", + menuButton: "text-gray-900 hover:bg-gray-100", + logoPrimary: "text-gray-900", + logoSecondary: "text-emerald-500", + activeLink: "text-emerald-500", + activeMobile: "text-emerald-500 bg-emerald-50", + }, +}; - const closeMenu = () => setMobileMenuOpen(false); +const buildLinks = (isLanding) => { + const prefix = isLanding ? "" : "/"; + return [ + { key: "features", label: "Features", href: `${prefix}#features`, isSection: true }, + { key: "about", label: "About", to: "/about" }, + { key: "how", label: "How it Works", href: `${prefix}#how-it-works`, isSection: true }, + { key: "pricing", label: "Pricing", href: `${prefix}#pricing`, isSection: true }, + { key: "faq", label: "FAQ", href: `${prefix}#faq`, isSection: true }, + { key: "contact", label: "Contact", to: "/contact" }, + ]; +}; - /* ---------------- FORCE RE-ANIMATION ON HOME ---------------- */ - const handleHomeClick = () => { - if (location.pathname === "/") { - window.scrollTo({ top: 0, behavior: "smooth" }); +export default function Navbar({ + tone = "light", + variant = "pill", + isLanding = false, + activeKey, + showThemeToggle = false, + showAuthButtons = true, + showDashboardButton = true, + onSectionClick, +}) { + const { token } = useSelector((state) => state.auth); + const navigate = useNavigate(); + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + const [scrollY, setScrollY] = useState(0); + const styles = NAV_TONES[tone] || NAV_TONES.light; + const links = useMemo(() => buildLinks(isLanding), [isLanding]); - // Force reload to replay animations - setTimeout(() => { - window.location.reload(); - }, 400); - } else { - navigate("/"); + useEffect(() => { + if (variant !== "simple") { + return undefined; } + const handleScroll = () => setScrollY(window.scrollY); + window.addEventListener("scroll", handleScroll); + return () => window.removeEventListener("scroll", handleScroll); + }, [variant]); + + const closeMobileMenu = () => { + setMobileMenuOpen(false); }; - /* ---------------- SMOOTH SCROLL ---------------- */ - const scrollToSection = (id) => { - if (location.pathname !== "/") { - navigate("/"); - setTimeout(() => { - const el = document.getElementById(id); - if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); - }, 200); - } else { - const el = document.getElementById(id); - if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); + const handleSectionClick = (event, sectionId) => { + if (onSectionClick) { + onSectionClick(event, sectionId); } - closeMenu(); + closeMobileMenu(); }; - /* ---------------- SPY NAVIGATION ---------------- */ - useEffect(() => { - const sections = ["features", "how-it-works", "pricing", "faq"]; - - const handleScroll = () => { - let current = ""; - sections.forEach((id) => { - const section = document.getElementById(id); - if (section) { - const rect = section.getBoundingClientRect(); - if (rect.top <= 120 && rect.bottom >= 120) { - current = id; - } - } - }); - setActiveSection(current); - }; - - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); - - const linkClass = (id) => - `relative cursor-pointer transition-colors duration-300 ${activeSection === id - ? "text-emerald-500" - : "text-gray-900 dark:text-gray-300 hover:text-emerald-500" - }`; + if (variant === "simple") { + return ( + + ); + } - {/* Desktop Links */} -
- scrollToSection("features")} className={linkClass("features")}> - Features - - - - About - - - scrollToSection("how-it-works")} className={linkClass("how-it-works")}> - How it Works - + return ( +