The Education component displays academic history in a visually engaging timeline format with animated cards and a flowing vertical progress line.
Overview
Key features:
- Vertical timeline with animated gradient line
- Alternating left/right card layout on desktop
- Animated dots marking each milestone
- Responsive mobile layout with all cards on one side
- GPA badges and duration indicators
- Smooth scroll-based animations
Component Structure
import React from 'react';
import { motion } from 'framer-motion';
import { styles } from '@/styles';
import { SectionWrapper } from '@/hooks';
const EducationCard = ({ degree, institution, duration, gpa, description, index, isLeft }) => (
<motion.div
initial={{ opacity: 0, x: isLeft ? -50 : 50 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: index * 0.2 }}
className="relative"
>
{/* Card content */}
</motion.div>
);
function Education() {
const educationData = [
{
degree: "Bachelor of Technology in Computer Science Engineering",
institution: "Techno Bengal Institute of Technology",
duration: "2023 - 2027 (Expected)",
gpa: "7.67 GPA",
description: "Currently in the third year..."
},
// More education entries...
];
return (
<div className="px-4 sm:px-6 lg:px-8 bg-white/50
dark:bg-zinc-950/30 backdrop-blur-sm py-16">
{/* Timeline */}
</div>
);
}
export default SectionWrapper(Education, "education");
Animated Timeline Line
The vertical line features a flowing gradient animation:
{/* Desktop Timeline */}
<div className="absolute left-1/2 transform -translate-x-1/2
top-0 bottom-0 w-1.5 hidden md:block">
<motion.div
initial={{ scaleY: 0 }}
whileInView={{ scaleY: 1 }}
viewport={{ once: true }}
transition={{ duration: 1.5, ease: "easeOut" }}
className="relative w-full h-full rounded-full origin-top overflow-hidden"
>
<div className="absolute inset-0 bg-gradient-to-b
from-navy-500 via-navy-600 to-transparent
dark:from-blue-500 dark:via-blue-600 dark:to-transparent" />
<motion.div
animate={{ y: ['100%', '-100%'] }}
transition={{ duration: 3, repeat: Infinity, ease: "linear" }}
className="absolute inset-0 bg-gradient-to-b
from-transparent via-white/30 to-transparent"
/>
</motion.div>
</div>
The flowing gradient creates a sense of progress and movement through academic history.
Education Card Component
const EducationCard = ({ degree, institution, duration, gpa, description, index, isLeft }) => (
<motion.div
initial={{ opacity: 0, x: isLeft ? -50 : 50 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: index * 0.2 }}
className="relative"
>
<div className="bg-white/95 dark:bg-zinc-900/20 backdrop-blur-sm
p-6 rounded-xl border border-navy-200 dark:border-zinc-600
hover:border-navy-400 dark:hover:border-zinc-500
transition-all duration-300 shadow-lg hover:shadow-xl group">
{/* Timeline Dot */}
<motion.div
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ delay: index * 0.2, duration: 0.4 }}
className={`absolute top-8 ${isLeft ? '-right-3' : '-left-3'}
md:block hidden`}
>
<div className="relative">
<div className="w-6 h-6 bg-navy-600 dark:bg-blue-500
rounded-full border-4 border-slate-50 dark:border-slate-900
shadow-lg" />
<div className="absolute inset-0 bg-navy-600 dark:bg-blue-500
rounded-full animate-ping opacity-20" />
</div>
</motion.div>
<h3 className="text-navy-900 dark:text-slate-100
text-xl font-bold mb-2">
{degree}
</h3>
<h4 className="text-navy-700 dark:text-slate-300
text-lg font-semibold mb-3">
{institution}
</h4>
<div className="flex items-center gap-4 mb-3">
<p className="text-navy-600 dark:text-slate-400
text-sm font-medium">
{duration}
</p>
{gpa && (
<span className="bg-navy-100 dark:bg-slate-700
text-navy-800 dark:text-slate-200
px-3 py-1 rounded-full text-sm font-semibold">
{gpa}
</span>
)}
</div>
<p className="text-navy-700 dark:text-slate-300
text-base leading-relaxed">
{description}
</p>
</div>
</motion.div>
);
Alternating Layout (Desktop)
<div className="space-y-12 relative">
{educationData.map((edu, index) => {
const isLeft = index % 2 === 0;
return (
<div key={index} className="relative">
{/* Desktop Layout - Alternating */}
<div className="hidden md:grid md:grid-cols-2 md:gap-16 items-center">
{isLeft ? (
<>
<EducationCard index={index} {...edu} isLeft={true} />
<div></div>
</>
) : (
<>
<div></div>
<EducationCard index={index} {...edu} isLeft={false} />
</>
)}
</div>
{/* Mobile Layout - All on right */}
<div className="md:hidden pl-12">
<EducationCard index={index} {...edu} isLeft={false} />
{/* Mobile Dot */}
<motion.div
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ delay: index * 0.2, duration: 0.4 }}
className="absolute left-4 top-8 transform -translate-x-1/2"
>
<div className="w-4 h-4 bg-navy-600 dark:bg-blue-500
rounded-full border-2 border-slate-50 dark:border-slate-900" />
</motion.div>
</div>
</div>
);
})}
</div>
Cards alternate between left and right sides with center timeline
All cards on right side with left timeline
Timeline Dots
Animated dots mark each milestone:
<motion.div
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
viewport={{ once: true }}
transition={{ delay: index * 0.2, duration: 0.4 }}
className={`absolute top-8 ${isLeft ? '-right-3' : '-left-3'}`}
>
<div className="relative">
{/* Main dot */}
<div className="w-6 h-6 bg-navy-600 dark:bg-blue-500
rounded-full border-4 border-slate-50 dark:border-slate-900
shadow-lg" />
{/* Pulse animation */}
<div className="absolute inset-0 bg-navy-600 dark:bg-blue-500
rounded-full animate-ping opacity-20" />
</div>
</motion.div>
The animate-ping class creates a subtle pulsing effect to draw attention.
Education Data Structure
const educationData = [
{
degree: "Bachelor of Technology in Computer Science Engineering",
institution: "Techno Bengal Institute of Technology",
duration: "2023 - 2027 (Expected)",
gpa: "7.67 GPA",
year: "2023",
description: "Currently in the third year of B.Tech..."
},
{
degree: "Higher Secondary (10+2 Grades)",
institution: "Bidhannagar Govt. High School",
duration: "2021 - 2023",
gpa: "84.2%",
year: "2021",
description: "Completed Higher Secondary examination..."
},
{
degree: "Secondary (10th Grade)",
institution: "Bidhannagar Municipal School",
duration: "2021",
gpa: "91.8%",
year: "2021",
description: "Completed Madhyamik examination..."
}
];
Animation Timing
Timeline Line
1.5s duration
Scales from top
scaleY: 0 → 1
Cards
0.6s duration
0.2s delay per card
Slide from sides
Dots
0.4s duration
0.2s delay per dot
Scale from center
GPA Badge
Optional GPA display with pill styling:
{gpa && (
<span className="bg-navy-100 dark:bg-slate-700
text-navy-800 dark:text-slate-200
px-3 py-1 rounded-full text-sm font-semibold">
{gpa}
</span>
)}
Mobile Timeline
Simplified for mobile devices:
{/* Mobile timeline line */}
<div className="absolute left-4 top-0 bottom-0 w-0.5 md:hidden
bg-gradient-to-b from-navy-500 to-navy-400
dark:from-blue-500 dark:to-blue-400" />
Responsive Behavior
- Two-column grid
- Cards alternate sides
- Center timeline (1.5px)
- Dots positioned on card edges
Hover Effects
hover:border-navy-400 dark:hover:border-zinc-500
hover:shadow-xl
The entire card responds to hover with:
- Border color change
- Shadow enhancement
- Smooth 300ms transition