minor fixes
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import Image from "next/image";
|
||||||
import { useEffect, useState, useRef } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import { FaGithub, FaLinkedin, FaExternalLinkAlt, FaStar, FaRocket, FaAward } from "react-icons/fa";
|
import { FaGithub, FaLinkedin, FaExternalLinkAlt, FaStar, FaRocket, FaAward } from "react-icons/fa";
|
||||||
import NeuralBackground from "../components/NeuralBackground";
|
import NeuralBackground from "../components/NeuralBackground";
|
||||||
@@ -130,9 +130,40 @@ function InfiniteCarousel() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function LoadingScreen() {
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-50 grid min-h-screen place-items-center overflow-hidden bg-[#0b1117] text-slate-200">
|
||||||
|
<div className="pointer-events-none absolute inset-0 -z-10 blur-2xl opacity-70 [background:radial-gradient(50%_50%_at_20%_0%,rgba(34,211,238,.16),transparent_60%),radial-gradient(45%_45%_at_85%_15%,rgba(20,184,166,.14),transparent_60%),radial-gradient(40%_40%_at_50%_120%,rgba(56,189,248,.12),transparent_60%)]" />
|
||||||
|
<div className="flex flex-col items-center gap-6">
|
||||||
|
<div className="relative h-20 w-20">
|
||||||
|
<div className="absolute inset-0 animate-[spin_1.2s_linear_infinite] rounded-full border-4 border-cyan-300/30 border-t-cyan-300 shadow-[0_0_24px_rgba(34,211,238,.35)]" />
|
||||||
|
<div className="absolute inset-2 grid place-items-center rounded-full bg-black/40 backdrop-blur-xl">
|
||||||
|
<Image
|
||||||
|
src="/ml4e.svg"
|
||||||
|
alt="ML4E"
|
||||||
|
width={44}
|
||||||
|
height={44}
|
||||||
|
priority
|
||||||
|
className="opacity-95 drop-shadow-[0_0_12px_rgba(34,211,238,.45)] animate-[pulse_1.8s_ease-in-out_infinite]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<h2 className="text-xl font-semibold tracking-wide text-cyan-200 drop-shadow-[0_0_16px_rgba(0,255,255,.35)]">
|
||||||
|
Loading Achievements
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm text-slate-400">
|
||||||
|
Fetching the latest achievements…
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function AchievementsPage() {
|
export default function AchievementsPage() {
|
||||||
const [achievements, setAchievements] = useState<Achievement[]>([]);
|
const [achievements, setAchievements] = useState<Achievement[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchAchievements() {
|
async function fetchAchievements() {
|
||||||
@@ -143,6 +174,8 @@ export default function AchievementsPage() {
|
|||||||
setAchievements(data);
|
setAchievements(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching achievements:", error);
|
console.error("Error fetching achievements:", error);
|
||||||
|
// Fallback to local achievements on error
|
||||||
|
setAchievements([]);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -152,6 +185,11 @@ export default function AchievementsPage() {
|
|||||||
|
|
||||||
const combinedAchievements = [...achievements];
|
const combinedAchievements = [...achievements];
|
||||||
|
|
||||||
|
// Show loading screen until data is fetched
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingScreen />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
@@ -167,12 +205,13 @@ export default function AchievementsPage() {
|
|||||||
</h1>
|
</h1>
|
||||||
<NeuralBackground/>
|
<NeuralBackground/>
|
||||||
|
|
||||||
|
|
||||||
<InfiniteCarousel />
|
<InfiniteCarousel />
|
||||||
|
|
||||||
<section className="mt-16 mb-16 flex flex-col gap-12 px-4 md:px-12 w-full max-w-7xl">
|
<section className="mt-16 mb-16 flex flex-col gap-12 px-4 md:px-12 w-full max-w-7xl">
|
||||||
{loading ? (
|
{combinedAchievements.length === 0 ? (
|
||||||
<p className="text-gray-400 text-center">Loading achievements...</p>
|
<div className="text-center text-gray-400 py-20">
|
||||||
|
<p className="text-xl">No achievements found.</p>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
combinedAchievements.map((achievement, idx) => {
|
combinedAchievements.map((achievement, idx) => {
|
||||||
const isImageLeft = idx % 2 === 0;
|
const isImageLeft = idx % 2 === 0;
|
||||||
@@ -234,16 +273,6 @@ function AchievementCard({ achievement, isImageLeft, index }: { achievement: Ach
|
|||||||
showContent ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'
|
showContent ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Styled Speech Bubble Tail - Pointing Left */}
|
|
||||||
{/* <div className="absolute left-0 top-1/2 -translate-x-[99%] -translate-y-1/2 z-20">
|
|
||||||
<div className="relative">
|
|
||||||
{/* Main triangular tail with same background as card */}
|
|
||||||
{/* <div className="w-0 h-0 border-t-[25px] border-t-transparent border-b-[25px] border-b-transparent border-r-[35px] border-r-slate-900/90 backdrop-blur-xl"></div> */}
|
|
||||||
{/* Gradient overlay to match card gradient */}
|
|
||||||
{/* <div className="absolute top-0 left-0 w-0 h-0 border-t-[25px] border-t-transparent border-b-[25px] border-b-transparent border-r-[35px] border-r-cyan-500/20 -translate-x-0.5"></div> */}
|
|
||||||
{/* </div> */}
|
|
||||||
{/* </div> */}
|
|
||||||
|
|
||||||
{/* Modern Card Design with enhanced glassmorphism */}
|
{/* Modern Card Design with enhanced glassmorphism */}
|
||||||
<div className="relative bg-gradient-to-br from-slate-900/80 to-blue-950/80 rounded-3xl p-8 text-white shadow-2xl border border-slate-700/50 backdrop-blur-2xl">
|
<div className="relative bg-gradient-to-br from-slate-900/80 to-blue-950/80 rounded-3xl p-8 text-white shadow-2xl border border-slate-700/50 backdrop-blur-2xl">
|
||||||
{/* Enhanced Glow Effect */}
|
{/* Enhanced Glow Effect */}
|
||||||
@@ -329,121 +358,111 @@ function AchievementCard({ achievement, isImageLeft, index }: { achievement: Ach
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* Content Box Left - Overlapping with higher z-index */}
|
{/* Content Box Left - Overlapping with higher z-index */}
|
||||||
<div
|
<div
|
||||||
className={`w-[50%] relative transition-all duration-1000 delay-500 -mr-20 z-30 ${
|
className={`w-[50%] relative transition-all duration-1000 delay-500 -mr-20 z-30 ${
|
||||||
showContent ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-20'
|
showContent ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-20'
|
||||||
}`}
|
}`}
|
||||||
>
|
|
||||||
{/* Styled Speech Bubble Tail - Pointing Right */}
|
|
||||||
{/* <div className="absolute right-0 top-1/2 translate-x-[99%] -translate-y-1/2 z-40">
|
|
||||||
<div className="relative">
|
|
||||||
{/* Main triangular tail with same background as card */}
|
|
||||||
{/* <div className="w-0 h-0 border-t-[25px] border-t-transparent border-b-[25px] border-b-transparent border-l-[35px] backdrop-blur-xl"></div> */}
|
|
||||||
{/* Gradient overlay to match card gradient */}
|
|
||||||
{/* <div className="absolute top-0 left-0 w-0 h-0 border-t-[25px] border-t-transparent border-b-[25px] border-b-transparent border-l-[35px] border-l-cyan-500/20 translate-x-0.5"></div> */}
|
|
||||||
{/* </div> */}
|
|
||||||
{/* </div> */}
|
|
||||||
|
|
||||||
{/* Modern Card Design with enhanced glassmorphism */}
|
|
||||||
<div className="relative bg-gradient-to-br from-slate-900/80 to-blue-950/80 rounded-3xl p-8 text-white shadow-2xl border border-slate-700/50 backdrop-blur-2xl z-30">
|
|
||||||
{/* Enhanced Glow Effect */}
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-l from-cyan-500/15 to-blue-500/15 rounded-3xl blur-2xl"></div>
|
|
||||||
|
|
||||||
{/* Header with Icon */}
|
|
||||||
<div className="flex items-center gap-3 mb-6 relative z-10">
|
|
||||||
<div className="p-2 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-xl shadow-lg">
|
|
||||||
<FaAward className="text-white text-sm" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-300 to-blue-300 text-sm font-bold tracking-widest uppercase font-[Orbitron]">
|
|
||||||
{startTyping && <TypingText text="Featured Achievement" speed={20} />}
|
|
||||||
</p>
|
|
||||||
<div className="flex gap-1 mt-1">
|
|
||||||
{[1, 2, 3].map((star) => (
|
|
||||||
<FaStar key={star} className="text-cyan-400 text-xs" />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Content */}
|
|
||||||
<h2 className="text-transparent bg-clip-text bg-gradient-to-r from-white via-cyan-100 to-blue-200 text-3xl font-bold mb-4 leading-tight font-[Orbitron] relative z-10">
|
|
||||||
{startTyping && <TypingText text={achievement.title} speed={25} />}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<p className="text-gray-300 text-base leading-relaxed mb-6 font-[Roboto] relative z-10">
|
|
||||||
{startTyping && <TypingText text={achievement.description || ""} speed={15} />}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* Technologies */}
|
|
||||||
{achievement.technologies && showContent && (
|
|
||||||
<div className="flex flex-wrap gap-3 mb-6 relative z-10">
|
|
||||||
{achievement.technologies.map((tech, i) => (
|
|
||||||
<span
|
|
||||||
key={i}
|
|
||||||
className="px-4 py-2 bg-slate-800/40 backdrop-blur-sm border border-slate-600/50 rounded-xl text-sm text-cyan-100 font-[Roboto] font-medium hover:bg-slate-700/60 transition-all duration-300 hover:scale-105 hover:border-cyan-500/30"
|
|
||||||
>
|
>
|
||||||
{tech}
|
{/* Modern Card Design with enhanced glassmorphism */}
|
||||||
</span>
|
<div className="relative bg-gradient-to-br from-slate-900/80 to-blue-950/80 rounded-3xl p-8 text-white shadow-2xl border border-slate-700/50 backdrop-blur-2xl z-30">
|
||||||
))}
|
{/* Enhanced Glow Effect */}
|
||||||
</div>
|
<div className="absolute inset-0 bg-gradient-to-l from-cyan-500/15 to-blue-500/15 rounded-3xl blur-2xl"></div>
|
||||||
)}
|
|
||||||
|
{/* Header with Icon */}
|
||||||
|
<div className="flex items-center gap-3 mb-6 relative z-10">
|
||||||
|
<div className="p-2 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-xl shadow-lg">
|
||||||
|
<FaAward className="text-white text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-300 to-blue-300 text-sm font-bold tracking-widest uppercase font-[Orbitron]">
|
||||||
|
{startTyping && <TypingText text="Featured Achievement" speed={20} />}
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-1 mt-1">
|
||||||
|
{[1, 2, 3].map((star) => (
|
||||||
|
<FaStar key={star} className="text-cyan-400 text-xs" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Content */}
|
||||||
<div className="flex items-center justify-between pt-4 border-t border-slate-700/50 relative z-10">
|
<h2 className="text-transparent bg-clip-text bg-gradient-to-r from-white via-cyan-100 to-blue-200 text-3xl font-bold mb-4 leading-tight font-[Orbitron] relative z-10">
|
||||||
<div className="flex items-center gap-4">
|
{startTyping && <TypingText text={achievement.title} speed={25} />}
|
||||||
{achievement.members && achievement.members.map((member, i) => (
|
</h2>
|
||||||
<a
|
|
||||||
key={i}
|
<p className="text-gray-300 text-base leading-relaxed mb-6 font-[Roboto] relative z-10">
|
||||||
href={member.linkedin}
|
{startTyping && <TypingText text={achievement.description || ""} speed={15} />}
|
||||||
target="_blank"
|
</p>
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center gap-2 text-cyan-200 hover:text-white transition-all duration-300 hover:scale-105 group"
|
{/* Technologies */}
|
||||||
>
|
{achievement.technologies && showContent && (
|
||||||
<div className="p-1.5 bg-slate-700/50 rounded-lg group-hover:bg-cyan-500/20 transition-colors">
|
<div className="flex flex-wrap gap-3 mb-6 relative z-10">
|
||||||
<FaLinkedin size={14} />
|
{achievement.technologies.map((tech, i) => (
|
||||||
|
<span
|
||||||
|
key={i}
|
||||||
|
className="px-4 py-2 bg-slate-800/40 backdrop-blur-sm border border-slate-600/50 rounded-xl text-sm text-cyan-100 font-[Roboto] font-medium hover:bg-slate-700/60 transition-all duration-300 hover:scale-105 hover:border-cyan-500/30"
|
||||||
|
>
|
||||||
|
{tech}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="flex items-center justify-between pt-4 border-t border-slate-700/50 relative z-10">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
{achievement.members && achievement.members.map((member, i) => (
|
||||||
|
<a
|
||||||
|
key={i}
|
||||||
|
href={member.linkedin}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 text-cyan-200 hover:text-white transition-all duration-300 hover:scale-105 group"
|
||||||
|
>
|
||||||
|
<div className="p-1.5 bg-slate-700/50 rounded-lg group-hover:bg-cyan-500/20 transition-colors">
|
||||||
|
<FaLinkedin size={14} />
|
||||||
|
</div>
|
||||||
|
<span className="text-sm font-[Roboto]">{member.name}</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{achievement.github && (
|
||||||
|
<a
|
||||||
|
href={achievement.github}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-2 text-cyan-200 hover:text-white transition-all duration-300 hover:scale-105 group"
|
||||||
|
>
|
||||||
|
<div className="p-2 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-lg shadow-lg group-hover:shadow-cyan-500/25 transition-all">
|
||||||
|
<FaExternalLinkAlt size={14} />
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Corner Accents */}
|
||||||
|
<div className="absolute top-0 left-0 w-20 h-20 bg-gradient-to-br from-cyan-500/20 to-transparent rounded-tl-3xl"></div>
|
||||||
|
<div className="absolute bottom-0 right-0 w-20 h-20 bg-gradient-to-tl from-blue-500/20 to-transparent rounded-br-3xl"></div>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm font-[Roboto]">{member.name}</span>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{achievement.github && (
|
|
||||||
<a
|
|
||||||
href={achievement.github}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="flex items-center gap-2 text-cyan-200 hover:text-white transition-all duration-300 hover:scale-105 group"
|
|
||||||
>
|
|
||||||
<div className="p-2 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-lg shadow-lg group-hover:shadow-cyan-500/25 transition-all">
|
|
||||||
<FaExternalLinkAlt size={14} />
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
)}
|
{/* Image Right - Larger with LOWER z-index so card overlaps it */}
|
||||||
</div>
|
<div
|
||||||
|
className={`w-[55%] relative h-[28rem] overflow-hidden rounded-2xl transition-all duration-1000 z-10 ${
|
||||||
{/* Corner Accents */}
|
isVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'
|
||||||
<div className="absolute top-0 left-0 w-20 h-20 bg-gradient-to-br from-cyan-500/20 to-transparent rounded-tl-3xl"></div>
|
}`}
|
||||||
<div className="absolute bottom-0 right-0 w-20 h-20 bg-gradient-to-tl from-blue-500/20 to-transparent rounded-br-3xl"></div>
|
>
|
||||||
</div>
|
<img
|
||||||
</div>
|
src={achievement.img}
|
||||||
|
alt={achievement.title}
|
||||||
{/* Image Right - Larger with LOWER z-index so card overlaps it */}
|
className="w-full h-full object-cover"
|
||||||
<div
|
/>
|
||||||
className={`w-[55%] relative h-[28rem] overflow-hidden rounded-2xl transition-all duration-1000 z-10 ${
|
<div className="absolute inset-0 bg-gradient-to-l from-transparent to-blue-950/30"></div>
|
||||||
isVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'
|
</div>
|
||||||
}`}
|
</>
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={achievement.img}
|
|
||||||
alt={achievement.title}
|
|
||||||
className="w-full h-full object-cover"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-l from-transparent to-blue-950/30"></div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { div } from "framer-motion/client";
|
|
||||||
|
|
||||||
const ANIMATIONS = {
|
const ANIMATIONS = {
|
||||||
overlay: {
|
overlay: {
|
||||||
@@ -10,7 +9,7 @@ const ANIMATIONS = {
|
|||||||
visible: { opacity: 1, transition: { duration: 0.3 } },
|
visible: { opacity: 1, transition: { duration: 0.3 } },
|
||||||
exit: { opacity: 0, transition: { duration: 0.3 } },
|
exit: { opacity: 0, transition: { duration: 0.3 } },
|
||||||
},
|
},
|
||||||
menuContainer: {
|
menuContainer: {
|
||||||
hidden: { opacity: 0 },
|
hidden: { opacity: 0 },
|
||||||
visible: {
|
visible: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
@@ -28,16 +27,42 @@ const ANIMATIONS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ✅ Define dropdown configurations
|
||||||
|
const DROPDOWN_CONFIG = {
|
||||||
|
Team: {
|
||||||
|
title: "Meet Our Team",
|
||||||
|
items: [
|
||||||
|
{ label: "Executive Body", href: "/team" },
|
||||||
|
{ label: "Team Members", href: "/teams" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Resources: {
|
||||||
|
title: "Resources",
|
||||||
|
items: [
|
||||||
|
{ label: "Online Resources", href: "/onlineresources" },
|
||||||
|
// { label: "Books", href: "/books" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ Direct link configurations
|
||||||
|
const DIRECT_LINKS = {
|
||||||
|
Home: "/",
|
||||||
|
Projects: "/projects",
|
||||||
|
Achievements: "/achievements",
|
||||||
|
Events: "/events",
|
||||||
|
};
|
||||||
|
|
||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [showDropdownResources, setShowDropdownResources] = useState(false);
|
const [activeDropdown, setActiveDropdown] = useState(null);
|
||||||
const [showDropDownTeams, setshowDropDownTeams] = useState(false);
|
|
||||||
|
|
||||||
// ✅ Fixed keyboard listener for JSX
|
// ✅ Fixed keyboard listener for JSX
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = (event) => {
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
setActiveDropdown(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,48 +94,175 @@ export default function Navbar() {
|
|||||||
"Contact",
|
"Contact",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ✅ Get href for any menu item
|
||||||
|
const getHref = (item) => {
|
||||||
|
if (DIRECT_LINKS[item]) return DIRECT_LINKS[item];
|
||||||
|
return `#${item.toLowerCase()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ Render mobile dropdown
|
||||||
|
const renderMobileDropdown = (item) => {
|
||||||
|
const config = DROPDOWN_CONFIG[item];
|
||||||
|
if (!config) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
key={item}
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
className="flex flex-col items-start w-full"
|
||||||
|
>
|
||||||
|
<motion.span
|
||||||
|
className="text-xl text-white font-semibold mb-2"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
{config.title}
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
{config.items.map((dropdownItem) => (
|
||||||
|
<motion.a
|
||||||
|
key={dropdownItem.href}
|
||||||
|
href={dropdownItem.href}
|
||||||
|
className="text-white text-base hover:text-blue-300"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
{dropdownItem.label}
|
||||||
|
</motion.a>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ Render desktop dropdown
|
||||||
|
// ✅ Render desktop dropdown
|
||||||
|
const renderDesktopDropdown = (item) => {
|
||||||
|
const config = DROPDOWN_CONFIG[item];
|
||||||
|
if (!config) return null;
|
||||||
|
|
||||||
|
const isActive = activeDropdown === item;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item}
|
||||||
|
className="relative group"
|
||||||
|
onMouseEnter={() => setActiveDropdown(item)}
|
||||||
|
onMouseLeave={() => setActiveDropdown(null)}
|
||||||
|
>
|
||||||
|
<motion.span
|
||||||
|
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5 cursor-pointer select-none backdrop-blur-sm"
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
>
|
||||||
|
{item} ▾
|
||||||
|
</motion.span>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{isActive && (
|
||||||
|
<motion.div
|
||||||
|
className="absolute top-full left-0 mt-2 flex flex-col rounded-xl shadow-2xl backdrop-blur-xl bg-white/15 border border-white/30"
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -10 }}
|
||||||
|
>
|
||||||
|
{config.items.map((dropdownItem) => (
|
||||||
|
<a
|
||||||
|
key={dropdownItem.href}
|
||||||
|
href={dropdownItem.href}
|
||||||
|
className="px-6 py-3 text-white hover:bg-white/20 transition-all duration-200 border-b border-white/10 last:border-b-0 first:rounded-t-xl last:rounded-b-xl"
|
||||||
|
onClick={() => setIsOpen(false)}
|
||||||
|
>
|
||||||
|
{dropdownItem.label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ Render regular menu item
|
||||||
|
const renderMenuItem = (item, isMobile = false) => {
|
||||||
|
// Check if it's a dropdown item
|
||||||
|
if (DROPDOWN_CONFIG[item]) {
|
||||||
|
return isMobile ? renderMobileDropdown(item) : renderDesktopDropdown(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular menu item
|
||||||
|
return (
|
||||||
|
<motion.a
|
||||||
|
key={item}
|
||||||
|
href={getHref(item)}
|
||||||
|
variants={ANIMATIONS.menuItem}
|
||||||
|
className={`${
|
||||||
|
isMobile
|
||||||
|
? "text-xl text-white hover:text-blue-300 transition-colors py-2 rounded-lg hover:bg-white/5 w-full text-left"
|
||||||
|
: "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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Logo component to avoid repetition
|
||||||
|
const Logo = () => (
|
||||||
|
<div className="w-12 h-12 rounded-full overflow-hidden">
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 500 500"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="w-full h-full"
|
||||||
|
>
|
||||||
|
<g transform="translate(0,500) scale(0.1,-0.1)" fill="#FFFFFF" stroke="none">
|
||||||
|
<path d="M0 2385 l0 -2385 2420 0 2420 0 0 2385 0 2385 -2420 0 -2420 0 0 -2385z m2400 1716 l0 -239 -62 -7 c-210 -23 -407 -82 -577 -171 -145 -76 -237 -142 -353 -252 -264 -252 -425 -568 -473 -930 -8 -62 -15 -115 -15 -118 0 -2 -108 -4 -240 -4 -186 0 -240 3 -240 13 0 54 35 293 56 382 65 272 198 551 373 780 64 85 232 256 321 328 330 267 766 435 1178 455 l32 2 0 -239z m287 163 c25 -5 48 -60 58 -139 l7 -50 30 60 c44 89 64 107 107 99 59 -10 71 -14 81 -35 9 -15 6 -24 -13 -42 -20 -18 -27 -41 -42 -143 l-18 -121 22 -22 c25 -25 26 -31 8 -55 -12 -16 -20 -17 -81 -8 -73 12 -96 24 -96 53 0 19 31 41 51 37 8 -2 17 22 25 67 18 100 16 107 -12 47 -28 -58 -52 -76 -88 -66 -29 7 -35 19 -51 99 l-12 60 -12 -88 c-7 -48 -12 -89 -10 -90 50 -27 60 -47 38 -73 -10 -13 -25 -14 -68 -9 -85 11 -103 20 -99 53 2 19 9 28 24 30 20 3 23 14 38 115 9 62 19 122 21 133 3 12 -2 27 -10 34 -19 16 -19 29 1 51 16 18 28 18 101 3z m825 -281 c48 -32 90 -66 94 -76 13 -40 -41 -62 -80 -32 -11 8 -23 15 -26 15 -6 0 -56 -71 -134 -192 l-17 -26 59 -41 59 -40 32 45 c26 37 36 45 59 42 43 -5 39 -42 -12 -113 -23 -33 -51 -61 -63 -63 -21 -3 -281 166 -295 192 -5 9 0 23 11 37 19 24 20 24 51 5 18 -10 35 -14 40 -10 4 5 37 54 74 109 l66 99 -25 26 c-29 31 -32 55 -7 69 24 14 16 17 114 -46z m-885 -314 c472 -52 882 -344 1088 -774 93 -195 129 -361 129 -590 0 -229 -36 -396 -129 -590 -73 -152 -63 -163 -133 137 -34 146 -62 271 -62 278 0 7 18 29 40 48 155 132 113 378 -77 459 -54 23 -149 20 -212 -8 -88 -37 -161 -143 -161 -233 0 -30 -8 -36 -207 -149 l-207 -118 -25 21 c-15 11 -51 33 -81 47 -53 26 -103 31 -197 20 -17 -1 -61 44 -208 213 -161 186 -185 218 -180 240 4 14 9 56 12 93 5 62 2 74 -26 132 -51 103 -136 155 -256 157 -102 2 -189 -50 -240 -144 -24 -44 -29 -65 -30 -123 0 -38 4 -86 8 -105 8 -35 7 -35 -183 -230 l-191 -195 6 108 c32 581 398 1064 942 1246 80 26 196 51 308 64 64 8 180 7 272 -4z m1579 -354 c9 -13 13 -33 10 -43 -4 -11 -49 -46 -102 -77 -61 -37 -94 -63 -93 -74 3 -32 -1 -41 -26 -57 -23 -15 -27 -15 -50 0 -26 17 -29 15 -25 -17 2 -24 -18 -47 -41 -47 -13 0 -33 22 -59 63 -46 71 -47 78 -21 101 15 14 24 15 40 6 12 -6 21 -15 21 -20 0 -6 5 -10 10 -10 18 0 11 21 -26 81 -29 48 -33 62 -24 79 16 29 49 34 272 38 93 2 98 1 114 -23z m-2381 -404 c74 -43 100 -151 52 -222 -24 -37 -97 -79 -137 -79 -35 0 -110 40 -132 70 -10 14 -21 42 -24 62 -24 143 117 241 241 169z m2574 -210 c18 -12 50 -326 34 -342 -6 -6 -42 -11 -79 -12 -66 -2 -69 -1 -72 22 -4 29 20 51 56 51 24 0 24 2 18 46 -3 26 -6 57 -6 70 0 21 -5 24 -40 24 -33 0 -40 -3 -40 -20 0 -13 7 -20 20 -20 23 0 43 -32 34 -54 -7 -17 -19 -21 -97 -31 -53 -7 -77 5 -77 36 0 10 9 24 20 31 11 7 20 20 20 29 0 14 -8 16 -42 12 -68 -8 -68 -7 -62 -60 10 -93 10 -92 53 -86 33 5 41 2 50 -16 21 -39 0 -58 -76 -66 -58 -6 -69 -5 -80 11 -7 10 -13 25 -13 33 0 9 -7 74 -15 145 -9 71 -13 137 -10 147 4 13 16 19 36 19 28 0 32 -4 44 -46 2 -7 38 -7 122 3 136 15 145 17 137 36 -6 16 21 47 39 47 7 0 18 -4 26 -9z m-949 -183 c138 -70 102 -268 -52 -285 -148 -17 -225 162 -115 265 48 45 104 51 167 20z m-1700 -21 c30 2 67 4 81 5 23 3 50 -24 208 -206 100 -115 181 -212 181 -216 0 -4 -7 -25 -16 -46 -25 -60 -15 -178 19 -237 94 -160 304 -196 441 -76 52 46 96 128 96 180 l0 37 203 116 c112 63 210 118 219 121 8 3 33 -5 53 -20 21 -14 48 -28 59 -31 18 -4 28 -36 80 -257 33 -139 72 -306 88 -372 l29 -120 -63 -59 c-209 -194 -433 -309 -708 -362 -128 -24 -361 -25 -485 -1 -436 85 -793 354 -989 745 -42 83 -109 275 -104 298 2 7 111 127 243 264 l240 251 35 -8 c19 -4 60 -7 90 -6z m-826 -304 c3 -21 8 -65 11 -98 10 -88 58 -268 98 -368 183 -453 571 -796 1040 -923 70 -18 282 -54 323 -54 2 0 3 -107 2 -237 l-3 -238 -70 3 c-162 7 -384 55 -560 122 -747 280 -1248 947 -1320 1758 l-6 72 240 0 239 0 6 -37z m3581 -40 c-42 -492 -237 -921 -574 -1267 -352 -360 -784 -562 -1308 -611 l-73 -7 0 240 0 240 63 7 c408 45 755 220 1025 518 209 231 354 565 387 890 l7 67 240 0 240 0 -7 -77z"/>
|
||||||
|
<path d="M3927 3254 c-5 -5 0 -17 29 -62 2 -4 104 58 104 64 0 7 -126 5 -133 -2z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Hamburger button component
|
||||||
|
const HamburgerButton = ({ onClick, isOpen, className = "" }) => (
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
aria-label="Toggle menu"
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
className={`flex flex-col justify-center items-center w-12 h-12 rounded-full border border-blue-500/20 bg-blue-500/10 backdrop-blur-sm transition-all ${className}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`block w-6 h-0.5 bg-blue-400 mb-1.5 transition-transform ${
|
||||||
|
isOpen ? "rotate-45 translate-y-2" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`block w-6 h-0.5 bg-blue-400 transition-opacity ${
|
||||||
|
isOpen ? "opacity-0" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`block w-6 h-0.5 bg-blue-400 mt-1.5 transition-transform ${
|
||||||
|
isOpen ? "-rotate-45 -translate-y-2" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* ---------------- MOBILE NAV ---------------- */}
|
{/* ---------------- MOBILE NAV ---------------- */}
|
||||||
<nav className="md:hidden fixed top-0 left-0 w-full bg-transparent z-[60] font-[Orbitron]">
|
<nav className="md:hidden fixed top-0 left-0 w-full bg-transparent z-[60] font-[Orbitron]">
|
||||||
<div className="flex justify-between items-center h-16 px-4">
|
<div className="flex justify-between items-center h-16 px-4">
|
||||||
{/* Logo */}
|
<Logo />
|
||||||
<div className="w-12 h-12 rounded-full overflow-hidden ">
|
<HamburgerButton
|
||||||
<svg
|
onClick={toggleMenu}
|
||||||
viewBox="0 0 500 500"
|
isOpen={isOpen}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
className={isOpen ? "fixed top-4 right-4 z-[70]" : "relative z-[60]"}
|
||||||
className="w-full h-full"
|
/>
|
||||||
>
|
|
||||||
<g transform="translate(0,500) scale(0.1,-0.1)" fill="#FFFFFF" stroke="none">
|
|
||||||
<path d="M0 2385 l0 -2385 2420 0 2420 0 0 2385 0 2385 -2420 0 -2420 0 0 -2385z m2400 1716 l0 -239 -62 -7 c-210 -23 -407 -82 -577 -171 -145 -76 -237 -142 -353 -252 -264 -252 -425 -568 -473 -930 -8 -62 -15 -115 -15 -118 0 -2 -108 -4 -240 -4 -186 0 -240 3 -240 13 0 54 35 293 56 382 65 272 198 551 373 780 64 85 232 256 321 328 330 267 766 435 1178 455 l32 2 0 -239z m287 163 c25 -5 48 -60 58 -139 l7 -50 30 60 c44 89 64 107 107 99 59 -10 71 -14 81 -35 9 -15 6 -24 -13 -42 -20 -18 -27 -41 -42 -143 l-18 -121 22 -22 c25 -25 26 -31 8 -55 -12 -16 -20 -17 -81 -8 -73 12 -96 24 -96 53 0 19 31 41 51 37 8 -2 17 22 25 67 18 100 16 107 -12 47 -28 -58 -52 -76 -88 -66 -29 7 -35 19 -51 99 l-12 60 -12 -88 c-7 -48 -12 -89 -10 -90 50 -27 60 -47 38 -73 -10 -13 -25 -14 -68 -9 -85 11 -103 20 -99 53 2 19 9 28 24 30 20 3 23 14 38 115 9 62 19 122 21 133 3 12 -2 27 -10 34 -19 16 -19 29 1 51 16 18 28 18 101 3z m825 -281 c48 -32 90 -66 94 -76 13 -40 -41 -62 -80 -32 -11 8 -23 15 -26 15 -6 0 -56 -71 -134 -192 l-17 -26 59 -41 59 -40 32 45 c26 37 36 45 59 42 43 -5 39 -42 -12 -113 -23 -33 -51 -61 -63 -63 -21 -3 -281 166 -295 192 -5 9 0 23 11 37 19 24 20 24 51 5 18 -10 35 -14 40 -10 4 5 37 54 74 109 l66 99 -25 26 c-29 31 -32 55 -7 69 24 14 16 17 114 -46z m-885 -314 c472 -52 882 -344 1088 -774 93 -195 129 -361 129 -590 0 -229 -36 -396 -129 -590 -73 -152 -63 -163 -133 137 -34 146 -62 271 -62 278 0 7 18 29 40 48 155 132 113 378 -77 459 -54 23 -149 20 -212 -8 -88 -37 -161 -143 -161 -233 0 -30 -8 -36 -207 -149 l-207 -118 -25 21 c-15 11 -51 33 -81 47 -53 26 -103 31 -197 20 -17 -1 -61 44 -208 213 -161 186 -185 218 -180 240 4 14 9 56 12 93 5 62 2 74 -26 132 -51 103 -136 155 -256 157 -102 2 -189 -50 -240 -144 -24 -44 -29 -65 -30 -123 0 -38 4 -86 8 -105 8 -35 7 -35 -183 -230 l-191 -195 6 108 c32 581 398 1064 942 1246 80 26 196 51 308 64 64 8 180 7 272 -4z m1579 -354 c9 -13 13 -33 10 -43 -4 -11 -49 -46 -102 -77 -61 -37 -94 -63 -93 -74 3 -32 -1 -41 -26 -57 -23 -15 -27 -15 -50 0 -26 17 -29 15 -25 -17 2 -24 -18 -47 -41 -47 -13 0 -33 22 -59 63 -46 71 -47 78 -21 101 15 14 24 15 40 6 12 -6 21 -15 21 -20 0 -6 5 -10 10 -10 18 0 11 21 -26 81 -29 48 -33 62 -24 79 16 29 49 34 272 38 93 2 98 1 114 -23z m-2381 -404 c74 -43 100 -151 52 -222 -24 -37 -97 -79 -137 -79 -35 0 -110 40 -132 70 -10 14 -21 42 -24 62 -24 143 117 241 241 169z m2574 -210 c18 -12 50 -326 34 -342 -6 -6 -42 -11 -79 -12 -66 -2 -69 -1 -72 22 -4 29 20 51 56 51 24 0 24 2 18 46 -3 26 -6 57 -6 70 0 21 -5 24 -40 24 -33 0 -40 -3 -40 -20 0 -13 7 -20 20 -20 23 0 43 -32 34 -54 -7 -17 -19 -21 -97 -31 -53 -7 -77 5 -77 36 0 10 9 24 20 31 11 7 20 20 20 29 0 14 -8 16 -42 12 -68 -8 -68 -7 -62 -60 10 -93 10 -92 53 -86 33 5 41 2 50 -16 21 -39 0 -58 -76 -66 -58 -6 -69 -5 -80 11 -7 10 -13 25 -13 33 0 9 -7 74 -15 145 -9 71 -13 137 -10 147 4 13 16 19 36 19 28 0 32 -4 44 -46 2 -7 38 -7 122 3 136 15 145 17 137 36 -6 16 21 47 39 47 7 0 18 -4 26 -9z m-949 -183 c138 -70 102 -268 -52 -285 -148 -17 -225 162 -115 265 48 45 104 51 167 20z m-1700 -21 c30 2 67 4 81 5 23 3 50 -24 208 -206 100 -115 181 -212 181 -216 0 -4 -7 -25 -16 -46 -25 -60 -15 -178 19 -237 94 -160 304 -196 441 -76 52 46 96 128 96 180 l0 37 203 116 c112 63 210 118 219 121 8 3 33 -5 53 -20 21 -14 48 -28 59 -31 18 -4 28 -36 80 -257 33 -139 72 -306 88 -372 l29 -120 -63 -59 c-209 -194 -433 -309 -708 -362 -128 -24 -361 -25 -485 -1 -436 85 -793 354 -989 745 -42 83 -109 275 -104 298 2 7 111 127 243 264 l240 251 35 -8 c19 -4 60 -7 90 -6z m-826 -304 c3 -21 8 -65 11 -98 10 -88 58 -268 98 -368 183 -453 571 -796 1040 -923 70 -18 282 -54 323 -54 2 0 3 -107 2 -237 l-3 -238 -70 3 c-162 7 -384 55 -560 122 -747 280 -1248 947 -1320 1758 l-6 72 240 0 239 0 6 -37z m3581 -40 c-42 -492 -237 -921 -574 -1267 -352 -360 -784 -562 -1308 -611 l-73 -7 0 240 0 240 63 7 c408 45 755 220 1025 518 209 231 354 565 387 890 l7 67 240 0 240 0 -7 -77z"/>
|
|
||||||
<path d="M3927 3254 c-5 -5 0 -17 29 -62 2 -4 104 58 104 64 0 7 -126 5 -133 -2z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={toggleMenu}
|
|
||||||
aria-label="Toggle menu"
|
|
||||||
aria-expanded={isOpen}
|
|
||||||
className={`flex flex-col justify-center items-center w-12 h-12 rounded-full border border-blue-500/20 bg-blue-500/10 backdrop-blur-sm transition-all
|
|
||||||
${isOpen ? "fixed top-4 right-4 z-[70]" : "relative z-[60]"}`}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={`block w-6 h-0.5 bg-blue-400 mb-1.5 transition-transform ${
|
|
||||||
isOpen ? "rotate-45 translate-y-2" : ""
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className={`block w-6 h-0.5 bg-blue-400 transition-opacity ${
|
|
||||||
isOpen ? "opacity-0" : ""
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className={`block w-6 h-0.5 bg-blue-400 mt-1.5 transition-transform ${
|
|
||||||
isOpen ? "-rotate-45 -translate-y-2" : ""
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
@@ -136,127 +288,7 @@ export default function Navbar() {
|
|||||||
className="flex flex-col items-start gap-6 w-full"
|
className="flex flex-col items-start gap-6 w-full"
|
||||||
variants={ANIMATIONS.menuContainer}
|
variants={ANIMATIONS.menuContainer}
|
||||||
>
|
>
|
||||||
{mainLinks.map((item) => {
|
{mainLinks.map((item) => renderMenuItem(item, true))}
|
||||||
// ✅ Mobile Team Dropdown
|
|
||||||
if (item === "Team") {
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key="team"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
className="flex flex-col items-start w-full"
|
|
||||||
>
|
|
||||||
<motion.span
|
|
||||||
className="text-xl text-white font-semibold mb-2"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
Meet Our Team
|
|
||||||
</motion.span>
|
|
||||||
|
|
||||||
<motion.div
|
|
||||||
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
<motion.a
|
|
||||||
href="/team"
|
|
||||||
className="text-white text-base hover:text-blue-300"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Executive Body
|
|
||||||
</motion.a>
|
|
||||||
<motion.a
|
|
||||||
href="/teams"
|
|
||||||
className="text-white text-base hover:text-blue-300"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Team Members
|
|
||||||
</motion.a>
|
|
||||||
</motion.div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Mobile Resources Dropdown
|
|
||||||
if (item === "Resources") {
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
key="resources"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
className="flex flex-col items-start w-full"
|
|
||||||
>
|
|
||||||
<motion.span
|
|
||||||
className="text-xl text-white font-semibold mb-2"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
Resources
|
|
||||||
</motion.span>
|
|
||||||
|
|
||||||
<motion.div
|
|
||||||
className="flex flex-col items-start gap-2 border-l-2 border-blue-500 pl-4"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
<motion.a
|
|
||||||
href="/onlineresources"
|
|
||||||
className="text-white text-base hover:text-blue-300"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Online Resources
|
|
||||||
</motion.a>
|
|
||||||
{/* <motion.a
|
|
||||||
href="/books"
|
|
||||||
className="text-white text-base hover:text-blue-300"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Books
|
|
||||||
</motion.a> */}
|
|
||||||
</motion.div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Direct links for Projects and Achievements
|
|
||||||
if (item === "Projects" || item === "Achievements") {
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`/${item.toLowerCase()}`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
className="text-xl text-white hover:text-blue-300 transition-colors py-2 rounded-lg hover:bg-white/5 w-full text-left"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</motion.a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (item === "Home") {
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`/`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
className="text-xl text-white hover:text-blue-300 transition-colors py-2 rounded-lg hover:bg-white/5 w-full text-left"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</motion.a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`#${item.toLowerCase()}`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
className="text-xl text-white hover:text-blue-300 transition-colors py-2 rounded-lg hover:bg-white/5 w-full text-left"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</motion.a>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</>
|
</>
|
||||||
@@ -274,32 +306,13 @@ export default function Navbar() {
|
|||||||
: "bg-white/10 backdrop-blur-lg border-r border-white/20 shadow-xl"
|
: "bg-white/10 backdrop-blur-lg border-r border-white/20 shadow-xl"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
<Logo />
|
||||||
{/* Logo */}
|
|
||||||
<div className="w-12 h-12 rounded-full overflow-hidden ">
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 500 500"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
className="w-full h-full"
|
|
||||||
>
|
|
||||||
<g transform="translate(0,500) scale(0.1,-0.1)" fill="#FFFFFF" stroke="none">
|
|
||||||
<path d="M0 2385 l0 -2385 2420 0 2420 0 0 2385 0 2385 -2420 0 -2420 0 0 -2385z m2400 1716 l0 -239 -62 -7 c-210 -23 -407 -82 -577 -171 -145 -76 -237 -142 -353 -252 -264 -252 -425 -568 -473 -930 -8 -62 -15 -115 -15 -118 0 -2 -108 -4 -240 -4 -186 0 -240 3 -240 13 0 54 35 293 56 382 65 272 198 551 373 780 64 85 232 256 321 328 330 267 766 435 1178 455 l32 2 0 -239z m287 163 c25 -5 48 -60 58 -139 l7 -50 30 60 c44 89 64 107 107 99 59 -10 71 -14 81 -35 9 -15 6 -24 -13 -42 -20 -18 -27 -41 -42 -143 l-18 -121 22 -22 c25 -25 26 -31 8 -55 -12 -16 -20 -17 -81 -8 -73 12 -96 24 -96 53 0 19 31 41 51 37 8 -2 17 22 25 67 18 100 16 107 -12 47 -28 -58 -52 -76 -88 -66 -29 7 -35 19 -51 99 l-12 60 -12 -88 c-7 -48 -12 -89 -10 -90 50 -27 60 -47 38 -73 -10 -13 -25 -14 -68 -9 -85 11 -103 20 -99 53 2 19 9 28 24 30 20 3 23 14 38 115 9 62 19 122 21 133 3 12 -2 27 -10 34 -19 16 -19 29 1 51 16 18 28 18 101 3z m825 -281 c48 -32 90 -66 94 -76 13 -40 -41 -62 -80 -32 -11 8 -23 15 -26 15 -6 0 -56 -71 -134 -192 l-17 -26 59 -41 59 -40 32 45 c26 37 36 45 59 42 43 -5 39 -42 -12 -113 -23 -33 -51 -61 -63 -63 -21 -3 -281 166 -295 192 -5 9 0 23 11 37 19 24 20 24 51 5 18 -10 35 -14 40 -10 4 5 37 54 74 109 l66 99 -25 26 c-29 31 -32 55 -7 69 24 14 16 17 114 -46z m-885 -314 c472 -52 882 -344 1088 -774 93 -195 129 -361 129 -590 0 -229 -36 -396 -129 -590 -73 -152 -63 -163 -133 137 -34 146 -62 271 -62 278 0 7 18 29 40 48 155 132 113 378 -77 459 -54 23 -149 20 -212 -8 -88 -37 -161 -143 -161 -233 0 -30 -8 -36 -207 -149 l-207 -118 -25 21 c-15 11 -51 33 -81 47 -53 26 -103 31 -197 20 -17 -1 -61 44 -208 213 -161 186 -185 218 -180 240 4 14 9 56 12 93 5 62 2 74 -26 132 -51 103 -136 155 -256 157 -102 2 -189 -50 -240 -144 -24 -44 -29 -65 -30 -123 0 -38 4 -86 8 -105 8 -35 7 -35 -183 -230 l-191 -195 6 108 c32 581 398 1064 942 1246 80 26 196 51 308 64 64 8 180 7 272 -4z m1579 -354 c9 -13 13 -33 10 -43 -4 -11 -49 -46 -102 -77 -61 -37 -94 -63 -93 -74 3 -32 -1 -41 -26 -57 -23 -15 -27 -15 -50 0 -26 17 -29 15 -25 -17 2 -24 -18 -47 -41 -47 -13 0 -33 22 -59 63 -46 71 -47 78 -21 101 15 14 24 15 40 6 12 -6 21 -15 21 -20 0 -6 5 -10 10 -10 18 0 11 21 -26 81 -29 48 -33 62 -24 79 16 29 49 34 272 38 93 2 98 1 114 -23z m-2381 -404 c74 -43 100 -151 52 -222 -24 -37 -97 -79 -137 -79 -35 0 -110 40 -132 70 -10 14 -21 42 -24 62 -24 143 117 241 241 169z m2574 -210 c18 -12 50 -326 34 -342 -6 -6 -42 -11 -79 -12 -66 -2 -69 -1 -72 22 -4 29 20 51 56 51 24 0 24 2 18 46 -3 26 -6 57 -6 70 0 21 -5 24 -40 24 -33 0 -40 -3 -40 -20 0 -13 7 -20 20 -20 23 0 43 -32 34 -54 -7 -17 -19 -21 -97 -31 -53 -7 -77 5 -77 36 0 10 9 24 20 31 11 7 20 20 20 29 0 14 -8 16 -42 12 -68 -8 -68 -7 -62 -60 10 -93 10 -92 53 -86 33 5 41 2 50 -16 21 -39 0 -58 -76 -66 -58 -6 -69 -5 -80 11 -7 10 -13 25 -13 33 0 9 -7 74 -15 145 -9 71 -13 137 -10 147 4 13 16 19 36 19 28 0 32 -4 44 -46 2 -7 38 -7 122 3 136 15 145 17 137 36 -6 16 21 47 39 47 7 0 18 -4 26 -9z m-949 -183 c138 -70 102 -268 -52 -285 -148 -17 -225 162 -115 265 48 45 104 51 167 20z m-1700 -21 c30 2 67 4 81 5 23 3 50 -24 208 -206 100 -115 181 -212 181 -216 0 -4 -7 -25 -16 -46 -25 -60 -15 -178 19 -237 94 -160 304 -196 441 -76 52 46 96 128 96 180 l0 37 203 116 c112 63 210 118 219 121 8 3 33 -5 53 -20 21 -14 48 -28 59 -31 18 -4 28 -36 80 -257 33 -139 72 -306 88 -372 l29 -120 -63 -59 c-209 -194 -433 -309 -708 -362 -128 -24 -361 -25 -485 -1 -436 85 -793 354 -989 745 -42 83 -109 275 -104 298 2 7 111 127 243 264 l240 251 35 -8 c19 -4 60 -7 90 -6z m-826 -304 c3 -21 8 -65 11 -98 10 -88 58 -268 98 -368 183 -453 571 -796 1040 -923 70 -18 282 -54 323 -54 2 0 3 -107 2 -237 l-3 -238 -70 3 c-162 7 -384 55 -560 122 -747 280 -1248 947 -1320 1758 l-6 72 240 0 239 0 6 -37z m3581 -40 c-42 -492 -237 -921 -574 -1267 -352 -360 -784 -562 -1308 -611 l-73 -7 0 240 0 240 63 7 c408 45 755 220 1025 518 209 231 354 565 387 890 l7 67 240 0 240 0 -7 -77z"/>
|
|
||||||
<path d="M3927 3254 c-5 -5 0 -17 29 -62 2 -4 104 58 104 64 0 7 -126 5 -133 -2z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!isOpen && (
|
{!isOpen && (
|
||||||
<button
|
<HamburgerButton
|
||||||
onClick={toggleMenu}
|
onClick={toggleMenu}
|
||||||
aria-label="Open menu"
|
isOpen={isOpen}
|
||||||
aria-expanded={isOpen}
|
/>
|
||||||
className="flex flex-col justify-center items-center w-12 h-12 rounded-full bg-blue-500/10 backdrop-blur-sm border border-blue-500/20"
|
|
||||||
>
|
|
||||||
<span className="block w-6 h-0.5 bg-blue-400 mb-1.5" />
|
|
||||||
<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>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="h-6" />
|
<div className="h-6" />
|
||||||
@@ -336,137 +349,7 @@ export default function Navbar() {
|
|||||||
className="flex flex-wrap items-center justify-center gap-6 max-w-4xl px-4"
|
className="flex flex-wrap items-center justify-center gap-6 max-w-4xl px-4"
|
||||||
variants={ANIMATIONS.menuContainer}
|
variants={ANIMATIONS.menuContainer}
|
||||||
>
|
>
|
||||||
{mainLinks.map((item) => {
|
{mainLinks.map((item) => renderMenuItem(item, false))}
|
||||||
// ✅ Desktop Team Dropdown
|
|
||||||
if (item === "Team") {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key="team"
|
|
||||||
className="relative group"
|
|
||||||
onMouseEnter={() => setshowDropDownTeams(true)}
|
|
||||||
onMouseLeave={() => setshowDropDownTeams(false)}
|
|
||||||
>
|
|
||||||
<motion.span
|
|
||||||
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5 cursor-pointer select-none"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
Meet Our Team ▾
|
|
||||||
</motion.span>
|
|
||||||
|
|
||||||
<AnimatePresence>
|
|
||||||
{showDropDownTeams && (
|
|
||||||
<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="/team"
|
|
||||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Executive Body
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="/teams"
|
|
||||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Team Members
|
|
||||||
</a>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Desktop Resources Dropdown
|
|
||||||
if (item === "Resources") {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key="resources"
|
|
||||||
className="relative group"
|
|
||||||
onMouseEnter={() => setShowDropdownResources(true)}
|
|
||||||
onMouseLeave={() => setShowDropdownResources(false)}
|
|
||||||
>
|
|
||||||
<motion.span
|
|
||||||
className="text-2xl text-white hover:text-blue-300 transition-colors py-2 px-6 rounded-lg hover:bg-white/5 cursor-pointer select-none"
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
>
|
|
||||||
Resources ▾
|
|
||||||
</motion.span>
|
|
||||||
|
|
||||||
<AnimatePresence>
|
|
||||||
{showDropdownResources && (
|
|
||||||
<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"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Online Resources
|
|
||||||
</a>
|
|
||||||
{/* <a
|
|
||||||
href="/books"
|
|
||||||
className="px-4 py-2 text-white hover:bg-blue-500/20"
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
|
||||||
Books
|
|
||||||
</a> */}
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ Direct links for Projects and Achievements
|
|
||||||
if (item === "Projects" || item === "Achievements") {
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`/${item.toLowerCase()}`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (item === "Home") {
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`/`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.a
|
|
||||||
key={item}
|
|
||||||
href={`${item.toLowerCase()==="events"?`/${item.toLowerCase()}`:`#${item.toLowerCase()}`}`}
|
|
||||||
variants={ANIMATIONS.menuItem}
|
|
||||||
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>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 10 KiB |
@@ -15,8 +15,8 @@ const geistMono = Geist_Mono({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: "Machine Learning for Everyone",
|
||||||
description: "Generated by create next app",
|
description: "This is the official website of ML4E, the official Machine Learning Club of NIT Rourkela.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
|
|||||||
Reference in New Issue
Block a user