Merge pull request #2 from AshwaniNITR/Shoaib's-branch
extension of resources navbar
This commit is contained in:
3
src/app/books/page.jsx
Normal file
3
src/app/books/page.jsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function BooksPage() {
|
||||
return <h1 className="text-center text-black mt-20">Books Page</h1>;
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
// Animation variants
|
||||
const ANIMATIONS = {
|
||||
overlay: {
|
||||
hidden: { opacity: 0 },
|
||||
@@ -30,15 +29,14 @@ const ANIMATIONS = {
|
||||
|
||||
export default function Navbar() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [showDropdown, setShowDropdown] = useState(false);
|
||||
|
||||
// Close on Esc
|
||||
useEffect(() => {
|
||||
const onKey = (e) => e.key === "Escape" && setIsOpen(false);
|
||||
window.addEventListener("keydown", onKey);
|
||||
return () => window.removeEventListener("keydown", onKey);
|
||||
}, []);
|
||||
|
||||
// Lock body scroll when open
|
||||
useEffect(() => {
|
||||
document.documentElement.classList.toggle("overflow-hidden", isOpen);
|
||||
return () => document.documentElement.classList.remove("overflow-hidden");
|
||||
@@ -46,6 +44,15 @@ export default function Navbar() {
|
||||
|
||||
const toggleMenu = () => setIsOpen((v) => !v);
|
||||
|
||||
const mainLinks = [
|
||||
"Home",
|
||||
"Events",
|
||||
"Projects",
|
||||
"Team",
|
||||
"Resources",
|
||||
"Contact",
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* ---------------- MOBILE NAV ---------------- */}
|
||||
@@ -54,7 +61,7 @@ export default function Navbar() {
|
||||
{/* Logo */}
|
||||
<div className="text-blue-500 text-2xl font-bold">ML4E</div>
|
||||
|
||||
{/* Hamburger / Cross button (moves to top-right & higher z when open) */}
|
||||
{/* Hamburger Button */}
|
||||
<button
|
||||
onClick={toggleMenu}
|
||||
aria-label="Toggle menu"
|
||||
@@ -84,7 +91,6 @@ export default function Navbar() {
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<>
|
||||
{/* Dark overlay behind button */}
|
||||
<motion.div
|
||||
className="fixed inset-0 bg-gray-900/95 z-40"
|
||||
variants={ANIMATIONS.overlay}
|
||||
@@ -93,7 +99,6 @@ export default function Navbar() {
|
||||
exit="exit"
|
||||
onClick={() => setIsOpen(false)}
|
||||
/>
|
||||
{/* Menu layer (below the floating button) */}
|
||||
<motion.div
|
||||
className="fixed inset-0 z-50 flex flex-col justify-center items-center"
|
||||
variants={ANIMATIONS.menuContainer}
|
||||
@@ -105,8 +110,40 @@ export default function Navbar() {
|
||||
className="flex flex-col items-center gap-6 px-4"
|
||||
variants={ANIMATIONS.menuContainer}
|
||||
>
|
||||
{["Home", "Events", "Projects", "Team", "Resources", "Contact"].map(
|
||||
(item) => (
|
||||
{mainLinks.map((item) => {
|
||||
if (item === "Resources") {
|
||||
return (
|
||||
<div
|
||||
key="resources"
|
||||
className="flex flex-col items-center"
|
||||
>
|
||||
<motion.button
|
||||
onClick={() => setShowDropdown(!showDropdown)}
|
||||
className="text-xl text-white hover:text-blue-300 transition-colors py-2 px-4 rounded-lg hover:bg-white/5"
|
||||
>
|
||||
Resources ▾
|
||||
</motion.button>
|
||||
{showDropdown && (
|
||||
<div className="flex flex-col items-center gap-2 mt-2">
|
||||
<a
|
||||
href="/onlineresources"
|
||||
className="text-white text-base hover:text-blue-300"
|
||||
>
|
||||
Online Resources
|
||||
</a>
|
||||
<a
|
||||
href="/books"
|
||||
className="text-white text-base hover:text-blue-300"
|
||||
>
|
||||
Books
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.a
|
||||
key={item}
|
||||
href={`#${item.toLowerCase()}`}
|
||||
@@ -116,8 +153,8 @@ export default function Navbar() {
|
||||
>
|
||||
{item}
|
||||
</motion.a>
|
||||
)
|
||||
)}
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</>
|
||||
@@ -125,7 +162,7 @@ export default function Navbar() {
|
||||
</AnimatePresence>
|
||||
</nav>
|
||||
|
||||
{/* ---------------- DESKTOP SIDEBAR ---------------- */}
|
||||
{/* ---------------- DESKTOP NAV ---------------- */}
|
||||
<div className="hidden md:block">
|
||||
<div
|
||||
className={`fixed top-0 left-0 h-screen w-20 flex flex-col justify-between items-center py-6 z-50
|
||||
@@ -138,8 +175,7 @@ export default function Navbar() {
|
||||
{/* Logo */}
|
||||
<div className="text-white text-2xl font-bold">ML4E</div>
|
||||
|
||||
{/* Desktop hamburger (does NOT turn into cross; cross is at top-right) */}
|
||||
{!isOpen?(
|
||||
{!isOpen && (
|
||||
<button
|
||||
onClick={toggleMenu}
|
||||
aria-label="Open menu"
|
||||
@@ -150,8 +186,7 @@ export default function Navbar() {
|
||||
<span className="block w-6 h-0.5 bg-blue-400" />
|
||||
<span className="block w-6 h-0.5 bg-blue-400 mt-1.5" />
|
||||
</button>
|
||||
):(null)}
|
||||
|
||||
)}
|
||||
|
||||
<div className="h-6" />
|
||||
</div>
|
||||
@@ -176,7 +211,6 @@ export default function Navbar() {
|
||||
animate="visible"
|
||||
exit="exit"
|
||||
>
|
||||
{/* Desktop cross at top-right only */}
|
||||
<button
|
||||
onClick={() => setIsOpen(false)}
|
||||
aria-label="Close menu"
|
||||
@@ -189,19 +223,61 @@ export default function Navbar() {
|
||||
className="flex flex-col md:flex-row md:flex-wrap items-center justify-center gap-6 max-w-4xl px-4"
|
||||
variants={ANIMATIONS.menuContainer}
|
||||
>
|
||||
{["Home", "Events", "Projects", "Team", "Resources", "Contact"].map(
|
||||
(item) => (
|
||||
{mainLinks.map((item) => {
|
||||
if (item === "Resources") {
|
||||
return (
|
||||
<div
|
||||
key="resources-desktop"
|
||||
className="relative group"
|
||||
onMouseEnter={() => setShowDropdown(true)}
|
||||
onMouseLeave={() => setShowDropdown(false)}
|
||||
>
|
||||
<motion.span
|
||||
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5"
|
||||
variants={ANIMATIONS.menuItem}
|
||||
>
|
||||
Resources ▾
|
||||
</motion.span>
|
||||
|
||||
<AnimatePresence>
|
||||
{showDropdown && (
|
||||
<motion.div
|
||||
className="absolute top-full left-0 mt-2 flex flex-col bg-white/10 border border-white/20 rounded-lg shadow-lg"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
>
|
||||
<a
|
||||
href="/onlineresources"
|
||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||
>
|
||||
Online Resources
|
||||
</a>
|
||||
<a
|
||||
href="/books"
|
||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
||||
>
|
||||
Books
|
||||
</a>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.a
|
||||
key={item}
|
||||
href={`#${item.toLowerCase()}`}
|
||||
variants={ANIMATIONS.menuItem}
|
||||
className="text-xl md:text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5"
|
||||
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
{item}
|
||||
</motion.a>
|
||||
)
|
||||
)}
|
||||
);
|
||||
})}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</>
|
||||
|
||||
5
src/app/onlineresources/page.jsx
Normal file
5
src/app/onlineresources/page.jsx
Normal file
@@ -0,0 +1,5 @@
|
||||
export default function OnlineResourcesPage() {
|
||||
return (
|
||||
<h1 className="text-center text-black mt-20">Online Resources Page</h1>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user