Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 152 additions & 125 deletions frontend/src/Components/Navbar/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// src/Components/Navbar/Navbar.jsx
import React, { useEffect, useState } from "react";
import {
UserCircle,
Expand All @@ -9,11 +8,10 @@ import {
Github,
Phone,
HelpCircle,
MessageCircle,
MessageSquarePlus
X,
} from "lucide-react";
import { FloatingNav } from "../ui/floating-navbar";
import { Link, useNavigate } from "react-router-dom";
import { FloatingNav } from "../ui/floating-navbar";
import DarkModeToggle from "../ui/DarkModeToggle";
import { useTimer } from "../../context/TimerContext";

Expand All @@ -26,16 +24,96 @@ const publicNavItems = [
{ name: "FAQ", link: "#faq", icon: <HelpCircle className="h-4 w-4" /> },
];

// --- Mobile Navigation Overlay Component (defined in the same file) ---
const MobileNavOverlay = ({ isOpen, onClose, navItems, isAuthenticated, handleLogout }) => {
const overlayClasses = `mobile-nav-overlay ${isOpen ? "open" : ""}`;

const handleLinkClick = () => {
onClose();
};

const handleLogoutClick = () => {
handleLogout();
onClose();
}

return (
<div className={overlayClasses}>
<button onClick={onClose} className="absolute top-8 right-8 text-foreground">
<X size={32} />
</button>
<nav className="flex flex-col items-center justify-center h-full">
<ul>
{!isAuthenticated ? (
navItems.map((item) => (
<li key={item.name}>
<a href={item.link} onClick={handleLinkClick}>
{item.name}
</a>
</li>
))
) : (
<>
<li>
<Link to="/profile" onClick={handleLinkClick}>
Profile
</Link>
</li>
{/* Add other authenticated links here */}
</>
)}
</ul>
</nav>

<div className="mobile-nav-footer">
{!isAuthenticated ? (
<>
<Link to="/register" className="w-full">
<button onClick={handleLinkClick} className="signup-btn-mobile">
Sign Up
</button>
</Link>
<DarkModeToggle />
</>
) : (
<>
<button onClick={handleLogoutClick} className="logout-btn-mobile">
Logout
</button>
<DarkModeToggle />
</>
)}
</div>
</div>
);
};


// --- Main Navbar Component ---
const Navbar = () => {
const [showFloating, setShowFloating] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const [displayTime, setDisplayTime] = useState("25:00");
const [isAuthenticated, setIsAuthenticated] = useState(
!!localStorage.getItem("token")
);
const [isAuthenticated, setIsAuthenticated] = useState(false);

const navigate = useNavigate();
const { timeLeft, isRunning } = useTimer();

useEffect(() => {
setIsAuthenticated(!!localStorage.getItem("token"));
}, []);

useEffect(() => {
const handleResize = () => {
if (window.innerWidth >= 1024) {
setMenuOpen(false);
}
};

window.addEventListener('resize', handleResize);

return () => window.removeEventListener('resize', handleResize);
}, []);

useEffect(() => {
const handleScroll = () => setShowFloating(window.scrollY > 100);
Expand Down Expand Up @@ -74,8 +152,6 @@ const Navbar = () => {
style={{ background: "var(--card)", borderColor: "var(--border)" }}
>
<div className="mx-auto mr-1 flex max-w-7xl items-center justify-between">
{/* Logo */}

<Link to="/">
<h1
className="text-2xl md:text-3xl lg:text-4xl font-extrabold tracking-tight hover:scale-105 transition-transform duration-300"
Expand All @@ -85,144 +161,94 @@ const Navbar = () => {
</h1>
</Link>

{/* Desktop Navigation - visible from lg */}
<nav className="hidden lg:flex space-x-6 lg:space-x-8 items-center">
{!isAuthenticated &&
publicNavItems.map((item) => (
<a
key={item.name}
href={item.link}
className="relative text-[15px] md:text-[16px] lg:text-[17px] font-medium transition-all duration-300 group flex items-center gap-2"
style={{ color: "var(--card-foreground)" }}
>
{item.icon} <span>{item.name}</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</a>
))}

{isAuthenticated && isRunning && (
<div
onClick={() => navigate("/pomodoro")}
className="flex items-center gap-2 cursor-pointer px-3 py-1 rounded-lg transition-all duration-300 hover:bg-gray-200 dark:hover:bg-gray-700 hover:shadow-md hover:shadow-[var(--primary)]/30"
>
<Clock className="w-5 h-5 text-blue-500 animate-pulse" />
<span className="text-sm font-mono">{displayTime}</span>
</div>
)}

{/* Auth Section */}
{isAuthenticated ? (
<div className="flex items-center gap-3 ml-4">
<Link
to="/profile"
className="flex items-center gap-2 text-[16px] lg:text-[17px] font-medium relative group"
style={{ color: "var(--primary)" }}
>
<UserCircle className="h-4 w-4" /> <span>Profile</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</Link>
<button
onClick={handleLogout}
className="text-[16px] lg:text-[17px] font-medium text-red-500 transition-colors duration-300 hover:text-red-600"
>
Logout
</button>
<DarkModeToggle />
</div>
) : (
<div className="flex items-center gap-3 ml-4">
<Link to="/register">
<button className="px-4 md:px-5 lg:px-6 py-2 rounded-md font-semibold bg-[var(--primary)] text-[var(--primary-foreground)] shadow-md transition-transform duration-300 hover:scale-105 hover:shadow-lg cursor-pointer text-sm md:text-base">
Sign Up
</button>
</Link>
<DarkModeToggle />
</div>
)}
{!isAuthenticated &&
publicNavItems.map((item) => (
<a
key={item.name}
href={item.link}
className="relative text-[15px] md:text-[16px] lg:text-[17px] font-medium transition-all duration-300 group flex items-center gap-2"
style={{ color: "var(--card-foreground)" }}
>
{item.icon} <span>{item.name}</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</a>
))}

{isAuthenticated && isRunning && (
<div
onClick={() => navigate("/pomodoro")}
className="flex items-center gap-2 cursor-pointer px-3 py-1 rounded-lg transition-all duration-300 hover:bg-gray-200 dark:hover:bg-gray-700 hover:shadow-md hover:shadow-[var(--primary)]/30"
>
<Clock className="w-5 h-5 text-blue-500 animate-pulse" />
<span className="text-sm font-mono">{displayTime}</span>
</div>
)}

{isAuthenticated ? (
<div className="flex items-center gap-3 ml-4">
<Link
to="/profile"
className="flex items-center gap-2 text-[16px] lg:text-[17px] font-medium relative group"
style={{ color: "var(--primary)" }}
>
<UserCircle className="h-4 w-4" /> <span>Profile</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</Link>
<button
onClick={handleLogout}
className="text-[16px] lg:text-[17px] font-medium text-red-500 transition-colors duration-300 hover:text-red-600"
>
Logout
</button>
<DarkModeToggle />
</div>
) : (
<div className="flex items-center gap-3 ml-4">
<Link to="/register">
<button className="px-4 md:px-5 lg:px-6 py-2 rounded-md font-semibold bg-[var(--primary)] text-[var(--primary-foreground)] shadow-md transition-transform duration-300 hover:scale-105 hover:shadow-lg cursor-pointer text-sm md:text-base">
Sign Up
</button>
</Link>
<DarkModeToggle />
</div>
)}
</nav>

{/* Mobile & Tablet Hamburger */}
<div className="lg:hidden">
<button
onClick={() => setMenuOpen(!menuOpen)}
className="relative w-8 h-6 flex flex-col justify-between items-center"
className="relative w-8 h-6 flex flex-col justify-between items-center z-[110]"
>
<span
className={`block h-1 w-full bg-current rounded transform transition duration-300 ease-in-out ${
menuOpen ? "rotate-45 translate-y-2" : ""
className={`block h-1 w-full rounded transform transition duration-300 ease-in-out ${
menuOpen ? "rotate-45 translate-y-[9px] bg-white" : "bg-current"
}`}
/>
<span
className={`block h-1 w-full bg-current rounded transition duration-300 ease-in-out ${
menuOpen ? "opacity-0" : ""
className={`block h-1 w-full rounded transition duration-300 ease-in-out ${
menuOpen ? "opacity-0" : "bg-current"
}`}
/>
<span
className={`block h-1 w-full bg-current rounded transform transition duration-300 ease-in-out ${
menuOpen ? "-rotate-45 -translate-y-2" : ""
className={`block h-1 w-full rounded transform transition duration-300 ease-in-out ${
menuOpen ? "-rotate-45 -translate-y-[9px] bg-white" : "bg-current"
}`}
/>
</button>

{menuOpen && (
<div className="mt-4 flex flex-col gap-3 px-4 pb-4">
{!isAuthenticated ? (
<>
{publicNavItems.map((item) => (
<a
key={item.name}
href={item.link}
className="relative text-[15px] md:text-[16px] font-medium transition-all duration-300 group flex items-center gap-2"
style={{ color: "var(--card-foreground)" }}
>
{item.icon} <span>{item.name}</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</a>
))}
<Link to="/register">
<button className="cursor-pointer w-full px-4 md:px-5 py-2 mt-2 rounded-md font-semibold bg-[var(--primary)] text-[var(--primary-foreground)] shadow-md transition-transform duration-300 hover:scale-105 hover:shadow-lg text-sm md:text-base">
Sign Up
</button>
</Link>
<DarkModeToggle />
</>
) : (
<>
<Link
to="/profile"
className="relative flex items-center gap-2 text-[16px] font-medium group"
style={{ color: "var(--primary)" }}
>
<UserCircle className="h-4 w-4" /> <span>Profile</span>
<span className="absolute left-0 -bottom-1 w-0 h-[2px] bg-gradient-to-r from-[var(--primary)] to-purple-500 transition-all duration-500 group-hover:w-full"></span>
</Link>
{isRunning && (
<div
onClick={() => navigate("/pomodoro")}
className="flex items-center gap-2 cursor-pointer hover:shadow-md hover:shadow-[var(--primary)]/30 transition-all duration-300"
>
<Clock className="w-5 h-5 text-blue-500 animate-pulse" />
<span className="text-sm font-mono">
{displayTime}
</span>
</div>
)}
<button
onClick={handleLogout}
className="text-[16px] font-medium text-red-500 hover:text-red-600 transition-colors"
>
Logout
</button>
<DarkModeToggle />
</>
)}
</div>
)}
</div>
</div>
</header>
)}

<MobileNavOverlay
isOpen={menuOpen}
onClose={() => setMenuOpen(false)}
navItems={publicNavItems}
isAuthenticated={isAuthenticated}
handleLogout={handleLogout}
/>

{showFloating && (
<FloatingNav navItems={!isAuthenticated ? publicNavItems : []} />
)}
Expand All @@ -231,3 +257,4 @@ const Navbar = () => {
};

export default Navbar;

Loading