fix:achievement

This commit is contained in:
Ashwani Senapati
2025-11-03 01:08:50 +05:30
parent 619489abec
commit 972b5118f0
3 changed files with 452 additions and 126 deletions

View File

@@ -1,40 +1,98 @@
"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import { Fondamento, Poppins } from "next/font/google";
import { FaGithub, FaLinkedin } from "react-icons/fa";
import { useEffect, useState, useRef } from "react";
import { FaGithub, FaLinkedin, FaExternalLinkAlt, FaStar, FaRocket, FaAward } from "react-icons/fa";
import NeuralBackground from "../components/NeuralBackground";
const orbitron = Fondamento({
subsets: ["latin"],
weight: ["400"],
});
function TypingText({ text, speed = 30, onComplete }: { text: string; speed?: number; onComplete?: () => void }) {
const [displayedText, setDisplayedText] = useState("");
const [currentIndex, setCurrentIndex] = useState(0);
const poppins = Poppins({
subsets: ["latin"],
weight: ["300", "400", "600"],
});
useEffect(() => {
if (currentIndex < text.length) {
const timeout = setTimeout(() => {
setDisplayedText(prev => prev + text[currentIndex]);
setCurrentIndex(prev => prev + 1);
}, speed);
return () => clearTimeout(timeout);
} else if (onComplete) {
onComplete();
}
}, [currentIndex, text, speed, onComplete]);
const localAchievements = [
return <>{displayedText}</>;
}
function useScrollAnimation() {
const [isVisible, setIsVisible] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.2 }
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) {
observer.unobserve(ref.current);
}
};
}, []);
return { ref, isVisible };
}
interface Achievement {
title: string;
description?: string;
img?: string;
members?: { name: string; linkedin: string }[];
github?: string;
technologies?: string[];
}
const localAchievements: Achievement[] = [
{
title: "Google Summer of Code (GSoC)",
img: "/trophy.png",
title: "HackOdisha 4.0",
description: "Developed a dynamic website for HO4 with MongoDB, 3D ID cards using Three.js, and achieved 5000+ page visits.",
img: "https://images.unsplash.com/photo-1504384308090-c894fdcc538d?w=800&q=80",
members: [
{ name: "Bibhu", linkedin: "https://linkedin.com/in/ml4e" },
],
github: "https://github.com/ml4e",
technologies: ["Next.js", "Tailwind", "Node.js", "MongoDB"],
},
{
title: "Google Summer of Code (GSoC) - Phase 2",
img: "/trophy.png",
title: "Google Summer of Code (GSoC)",
description: "Successfully completed GSoC contributing to open source projects with innovative solutions and community impact.",
img: "https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=800&q=80",
members: [
{ name: "Sonali Lipsa Patra", linkedin: "https://linkedin.com/in/ml4e" },
],
github: "https://github.com/ml4e",
technologies: ["Python", "Django", "React", "Docker"],
},
{
title: "Flipkart GRiD Challenge",
description: "Participated in Flipkart's innovation challenge, developing cutting-edge solutions for e-commerce problems.",
img: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80",
members: [
{ name: "Team Lead", linkedin: "https://linkedin.com/in/ml4e" },
],
github: "https://github.com/ml4e",
technologies: ["Machine Learning", "Python", "TensorFlow"],
},
];
const marqueeItems = [
"Google Summer of Code",
"HackFest — AI Hackathon",
@@ -72,10 +130,9 @@ function InfiniteCarousel() {
}
export default function AchievementsPage() {
const [achievements, setAchievements] = useState([]);
const [loading, setLoading] = useState(true);
const [achievements, setAchievements] = useState<Achievement[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
async function fetchAchievements() {
try {
@@ -92,123 +149,388 @@ export default function AchievementsPage() {
fetchAchievements();
}, []);
const combinedAchievements = [...localAchievements, ...achievements];
const combinedAchievements = [...achievements];
return (
<main
className={`relative min-h-screen flex flex-col items-center justify-start bg-gradient-to-b from-black via-blue-950 to-black text-white ${orbitron.className}`}
>
<div className="fixed bottom-4 left-4 w-50 md:w-78 opacity-90 z-10 animate-trophy">
<Image
src="/trophy.png"
alt="Trophy"
width={300}
height={300}
className="object-contain drop-shadow-[0_0_25px_rgba(0,120,255,0.8)]"
/>
</div>
<style jsx>{`
@keyframes trophyScale {
0% {
transform: scale(1);
filter: drop-shadow(0 0 10px rgba(0, 120, 255, 0.5));
}
50% {
transform: scale(0.9);
filter: drop-shadow(0 0 25px rgba(0, 180, 255, 0.8));
}
100% {
transform: scale(1);
filter: drop-shadow(0 0 10px rgba(0, 120, 255, 0.5));
}
}
.animate-trophy {
animation: trophyScale 4s ease-in-out infinite;
}
<main className="relative min-h-screen flex flex-col items-center justify-start bg-gradient-to-b from-black via-blue-950 to-black text-white font-[Orbitron,Roboto,sans-serif]">
<style jsx global>{`
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;900&family=Roboto:wght@300;400;500;700&display=swap');
`}</style>
<h1
className={`text-4xl md:text-6xl font-bold mt-24 text-center tracking-widest relative ${orbitron.className}`}
>
<h1 className="text-4xl md:text-6xl font-bold mt-24 text-center tracking-widest relative font-[Orbitron]">
<span className="relative text-transparent bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-300 to-blue-600 drop-shadow-[0_0_25px_rgba(0,200,255,0.6)]">
ACHIEVEMENTS
</span>
<div className="absolute -bottom-2 left-1/2 transform -translate-x-1/2 w-24 h-[3px] bg-gradient-to-r from-blue-500 to-cyan-400 rounded-full" />
</h1>
<NeuralBackground/>
<InfiniteCarousel />
<section
className={`mt-10 mb-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 px-4 md:px-12 w-full max-w-6xl ${poppins.className}`}
>
<section className="mt-16 mb-16 flex flex-col gap-12 px-4 md:px-12 w-full max-w-7xl">
{loading ? (
<p className="text-gray-400 text-center col-span-full">Loading achievements...</p>
<p className="text-gray-400 text-center">Loading achievements...</p>
) : (
combinedAchievements.map((a, idx) => (
<div
key={idx}
className={`group relative bg-gradient-to-br from-blue-900/40 to-blue-800/10 border border-blue-700 rounded-xl overflow-hidden backdrop-blur-sm transition-transform duration-300 transform hover:scale-[1.04] hover:shadow-[0_0_25px_rgba(0,120,255,0.6)] flex flex-col ${
a.img ? "" : "justify-center"
}`}
>
combinedAchievements.map((achievement, idx) => {
const isImageLeft = idx % 2 === 0;
{a.img && (
<div className="w-full h-48 relative overflow-hidden">
<Image
src={a.img}
alt={a.title}
fill
className="object-cover group-hover:scale-105 transition-transform duration-700"
/>
<div className="absolute inset-0 bg-blue-400/10 opacity-0 group-hover:opacity-100 transition-opacity duration-700 blur-2xl"></div>
</div>
)}
<div className="p-6 flex flex-col flex-grow text-center">
<h2 className="text-2xl font-semibold mb-2 text-blue-200">
{a.title}
</h2>
{a.members && (
<div className="flex justify-center items-center mt-3 flex-wrap gap-3">
{a.members.map((m, i) => (
<a
key={i}
href={m.linkedin}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 hover:text-blue-400 text-white/80 transition"
>
<span className="text-xs">{m.name}</span>
<FaLinkedin size={14} />
</a>
))}
</div>
)}
{a.github && (
<a
href={a.github}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 text-white/80 hover:text-white mt-4"
>
<FaGithub size={18} />
<span className="text-sm">GitHub</span>
</a>
)}
</div>
</div>
))
return (
<AchievementCard
key={idx}
achievement={achievement}
isImageLeft={isImageLeft}
index={idx}
/>
);
})
)}
</section>
</main>
);
}
function AchievementCard({ achievement, isImageLeft, index }: { achievement: Achievement; isImageLeft: boolean; index: number }) {
const { ref, isVisible } = useScrollAnimation();
const [showContent, setShowContent] = useState(false);
const [startTyping, setStartTyping] = useState(false);
useEffect(() => {
if (isVisible) {
const timer = setTimeout(() => {
setShowContent(true);
setTimeout(() => setStartTyping(true), 300);
}, 500);
return () => clearTimeout(timer);
}
}, [isVisible]);
return (
<div ref={ref} className="w-full">
{/* Desktop Layout */}
<div className="hidden md:flex gap-0 items-center relative">
{isImageLeft ? (
<>
{/* Image Left - Larger */}
<div
className={`w-[55%] relative h-[28rem] overflow-hidden rounded-2xl transition-all duration-1000 ${
isVisible ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-20'
}`}
>
<img
src={achievement.img}
alt={achievement.title}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-r from-transparent to-blue-950/30"></div>
</div>
{/* Content Box Right - Overlapping */}
<div
className={`w-[50%] relative transition-all duration-1000 delay-500 -ml-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 */}
<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 */}
<div className="absolute inset-0 bg-gradient-to-r 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">
<FaRocket 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}
</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 right-0 w-20 h-20 bg-gradient-to-bl from-cyan-500/20 to-transparent rounded-tr-3xl"></div>
<div className="absolute bottom-0 left-0 w-20 h-20 bg-gradient-to-tr from-blue-500/20 to-transparent rounded-bl-3xl"></div>
</div>
</div>
</>
) : (
<>
{/* Content Box Left - Overlapping with higher z-index */}
<div
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'
}`}
>
{/* 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}
</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>
{/* Image Right - Larger with LOWER z-index so card overlaps it */}
<div
className={`w-[55%] relative h-[28rem] overflow-hidden rounded-2xl transition-all duration-1000 z-10 ${
isVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'
}`}
>
<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>
{/* Mobile Layout - Modern */}
<div className="md:hidden relative">
<div className="relative h-80 rounded-2xl overflow-hidden mb-6">
<img
src={achievement.img}
alt={achievement.title}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent"></div>
</div>
{/* Modern Mobile Card */}
<div className="relative bg-gradient-to-br from-slate-900 to-blue-950 rounded-3xl p-6 text-white shadow-2xl border border-slate-700/50 backdrop-blur-lg">
{/* Glow Effect */}
<div className="absolute inset-0 bg-gradient-to-r from-cyan-500/10 to-blue-500/10 rounded-3xl blur-xl"></div>
{/* Header with Icon */}
<div className="flex items-center gap-3 mb-4 relative z-10">
<div className="p-2 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-lg shadow-lg">
<FaRocket className="text-white text-xs" />
</div>
<div>
<p className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-300 to-blue-300 text-xs font-bold tracking-widest uppercase font-[Orbitron]">
{startTyping && <TypingText text="Featured" 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 to-cyan-200 text-2xl font-bold mb-3 leading-tight font-[Orbitron] relative z-10">
{startTyping && <TypingText text={achievement.title} speed={25} />}
</h2>
<p className="text-gray-300 text-sm leading-relaxed mb-4 font-[Roboto] relative z-10">
{startTyping && <TypingText text={achievement.description || ""} speed={15} />}
</p>
{/* Technologies */}
{achievement.technologies && showContent && (
<div className="flex flex-wrap gap-2 mb-4 relative z-10">
{achievement.technologies.map((tech, i) => (
<span
key={i}
className="px-3 py-1.5 bg-slate-800/60 backdrop-blur-sm border border-slate-600/50 rounded-lg text-xs text-cyan-100 font-[Roboto] font-medium"
>
{tech}
</span>
))}
</div>
)}
{/* Footer */}
<div className="flex items-center justify-between pt-3 border-t border-slate-700/50 relative z-10">
<div className="flex items-center gap-3">
{achievement.members && achievement.members[0] && (
<a
href={achievement.members[0].linkedin}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-cyan-200 hover:text-white transition-colors"
>
<FaLinkedin size={12} />
<span className="text-xs font-[Roboto]">{achievement.members[0].name}</span>
</a>
)}
</div>
{achievement.github && (
<a
href={achievement.github}
target="_blank"
rel="noopener noreferrer"
className="p-1.5 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-lg shadow-lg text-white"
>
<FaExternalLinkAlt size={12} />
</a>
)}
</div>
{/* Corner Accents */}
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-bl from-cyan-500/20 to-transparent rounded-tr-3xl"></div>
<div className="absolute bottom-0 left-0 w-16 h-16 bg-gradient-to-tr from-blue-500/20 to-transparent rounded-bl-3xl"></div>
</div>
</div>
</div>
);
}

View File

@@ -7,10 +7,10 @@ export async function POST(req) {
await connectToAchievementsDB(); // ✅ connect to DB
const formData = await req.formData();
const title = formData.get("title");
const github = formData.get("github");
const deployed = formData.get("deployed"); // ✅ new
console.log("📥 Received form data for new achievement.", formData);
const title = formData.get("achievementName");
const github = formData.get("githubLink");
const deployed = formData.get("deployedLink"); // ✅ new
const dateOfEvent = formData.get("dateOfEvent"); // ✅ new
const membersRaw = formData.get("members");
const certificate = formData.get("certificate");

View File

@@ -4,6 +4,9 @@ import React from "react";
import { FaLinkedin, FaEnvelope } from "react-icons/fa";
import ProfileCard from "@/app/components/ProfileCard/ProfileCard";
import TextType from "@/app/components/TextType/TextType"; // ✅ Typing effect component
import NeuralBackground from "@/app/components/NeuralBackground";
const Glow = ({ className = "" }) => (
<div
@@ -74,6 +77,7 @@ export default function TeamPage() {
"
>
<Glow />
<NeuralBackground/>
{/* ⚡ Neon Typing Heading */}
<div className="relative text-center pt-12 pb-8">