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
164 changes: 143 additions & 21 deletions src/components/EventCard.jsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,166 @@
import React, { useState, useEffect } from "react";
import {
FaChevronLeft,
FaChevronRight,
FaCalendar,
FaMapMarkerAlt,
} from "react-icons/fa";

const EventCard = ({ title, description, images }) => {
const EventCard = ({ title, description, images, date, location, status }) => {
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [isHovered, setIsHovered] = useState(false);

// Auto-change image every 3 seconds
// Auto-change image every 3 seconds (paused on hover)
useEffect(() => {
if (!images || images.length <= 1) return; // skip if 0 or 1 image
if (!images || images.length <= 1 || isHovered) return;

const interval = setInterval(() => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % images.length);
}, 3000);

return () => clearInterval(interval);
}, [images]);
}, [images, isHovered]);

const goToNextImage = () => {
if (images && images.length > 1) {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % images.length);
}
};

const goToPrevImage = () => {
if (images && images.length > 1) {
setCurrentImageIndex((prevIndex) =>
prevIndex === 0 ? images.length - 1 : prevIndex - 1,
);
}
};

const goToImage = (index) => {
setCurrentImageIndex(index);
};

const getStatusColor = (status) => {
switch (status?.toLowerCase()) {
case "upcoming":
return "bg-blue-50 text-blue-600 border-blue-200";
case "ongoing":
return "bg-green-50 text-green-600 border-green-200";
case "completed":
return "bg-gray-50 text-gray-600 border-gray-200";
default:
return "bg-gray-50 text-gray-600 border-gray-200";
}
};

return (
<div className="bg-gray-50 rounded-xl shadow-md overflow-hidden flex flex-col md:flex-row border-2 border-[#0B2044]">
<div className="relative w-full md:w-2/5 flex-shrink-0">
<div className="w-full aspect-[16/9] relative overflow-hidden rounded-l-xl">
<img
src={images?.[currentImageIndex]}
alt={`${title} image ${currentImageIndex + 1}`}
className="w-full h-full object-cover transition-all duration-500 absolute top-0 left-0"
/>
<div
className="bg-white rounded-xl shadow-md hover:shadow-lg overflow-hidden border border-gray-100 transition-all duration-300 hover:-translate-y-1 max-w-sm w-full"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* Image Section */}
<div className="relative">
<div className="w-full h-48 relative overflow-hidden">
{images && images.length > 0 ? (
<>
<img
src={images[currentImageIndex]}
alt={`${title} image ${currentImageIndex + 1}`}
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
loading="lazy"
/>

{/* Navigation Controls (show on hover if multiple images) */}
{images.length > 1 && (
<>
<button
onClick={goToPrevImage}
className="absolute left-2 top-1/2 transform -translate-y-1/2 bg-white/90 hover:bg-white text-gray-700 p-1.5 rounded-full shadow-md opacity-0 hover:opacity-100 transition-all duration-300"
aria-label="Previous image"
>
<FaChevronLeft size={10} />
</button>

<button
onClick={goToNextImage}
className="absolute right-2 top-1/2 transform -translate-y-1/2 bg-white/90 hover:bg-white text-gray-700 p-1.5 rounded-full shadow-md opacity-0 hover:opacity-100 transition-all duration-300"
aria-label="Next image"
>
<FaChevronRight size={10} />
</button>
</>
)}

{/* Status Badge */}
{status && (
<div className="absolute top-3 left-3">
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${getStatusColor(status)}`}
>
{status}
</span>
</div>
)}
</>
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<div className="text-center">
<div className="text-2xl text-gray-400 mb-1">📸</div>
<p className="text-gray-500 text-xs">No image</p>
</div>
</div>
)}
</div>

{images?.length > 1 && (
<div className="absolute bottom-2 left-2/5 transform -translate-x-1/2 flex gap-1">
{/* Image Indicators */}
{images && images.length > 1 && (
<div className="absolute bottom-2 left-1/2 transform -translate-x-1/2 flex gap-1">
{images.map((_, idx) => (
<span
<button
key={idx}
className={`h-2 w-2 rounded-full ${
idx === currentImageIndex ? "bg-white" : "bg-gray-400"
onClick={() => goToImage(idx)}
className={`h-1.5 w-1.5 rounded-full transition-all duration-200 ${
idx === currentImageIndex
? "bg-white scale-125"
: "bg-white/60 hover:bg-white/80"
}`}
></span>
aria-label={`Go to image ${idx + 1}`}
/>
))}
</div>
)}
</div>
<div className="p-4 flex flex-col justify-center">
<h3 className="text-2xl font-semibold text-[#0B2044]">{title}</h3>
<p className="text-base text-gray-600 mt-2">{description}</p>

{/* Content Section */}
<div className="p-5">
<h3 className="text-lg font-semibold text-[#0B2044] mb-2 line-clamp-2">
{title || "Event Title"}
</h3>

<p className="text-gray-600 text-sm mb-4 line-clamp-3">
{description || "Event description will be displayed here."}
</p>

{/* Event Meta Information */}
<div className="space-y-2 mb-4">
{date && (
<div className="flex items-center text-xs text-gray-500">
<FaCalendar className="w-3 h-3 mr-2" />
<span>{date}</span>
</div>
)}
{location && (
<div className="flex items-center text-xs text-gray-500">
<FaMapMarkerAlt className="w-3 h-3 mr-2" />
<span>{location}</span>
</div>
)}
</div>

{/* Action Button */}
<button className="w-full px-4 py-2 bg-[#0B2044] text-white text-sm font-medium rounded-lg hover:bg-blue-700 transition-colors duration-200">
View Details
</button>
</div>
</div>
);
Expand Down
55 changes: 51 additions & 4 deletions src/components/MissionCard.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,55 @@
export default function MissionCard({ title, description }) {
export default function MissionCard({ title, description, index }) {
return (
<div className="bg-[#0A1440] text-white w-80 h-72 rounded-xl shadow-lg hover:shadow-2xl transition-all duration-300 p-8 flex flex-col justify-center items-center text-center hover:scale-105 border border-gray-700/30">
<h4 className="font-bold text-2xl mb-6 leading-tight">{title}</h4>
<p className="text-gray-200 text-base leading-relaxed">{description}</p>
<div className="relative bg-[#0A1440] text-white rounded-2xl shadow-xl hover:shadow-2xl transition-all duration-500 p-8 group overflow-hidden transform hover:-translate-y-1">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-5 bg-gradient-to-r from-white/10 to-transparent"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-white/5 rounded-full -translate-y-16 translate-x-16 group-hover:scale-110 transition-transform duration-700"></div>
<div className="absolute bottom-0 left-0 w-24 h-24 bg-white/3 rounded-full translate-y-12 -translate-x-12 group-hover:scale-125 transition-transform duration-700"></div>

{/* Content */}
<div className="relative z-10 h-full flex flex-col justify-center items-start text-left min-h-[280px]">
{/* Icon or Number */}
<div className="mb-6">
<div className="w-14 h-14 bg-white/10 backdrop-blur-sm rounded-xl flex items-center justify-center group-hover:scale-110 group-hover:bg-white/15 transition-all duration-300">
<span className="text-2xl font-bold text-white">
{(index + 1).toString().padStart(2, "0")}
</span>
</div>
</div>

{/* Title */}
<h4 className="font-bold text-2xl mb-4 leading-tight text-white group-hover:text-white/95 transition-colors duration-300">
{title}
</h4>

{/* Description */}
<p className="text-white/80 text-base leading-relaxed group-hover:text-white/90 transition-colors duration-300">
{description}
</p>

{/* Hover Effect Arrow */}
<div className="mt-6 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0">
<div className="flex items-center text-white/90 text-sm font-medium">
<span className="mr-2">Learn More</span>
<svg
className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</div>
</div>
</div>

{/* Hover Overlay */}
<div className="absolute inset-0 bg-gradient-to-br from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
</div>
);
}
78 changes: 73 additions & 5 deletions src/components/MissionSection.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,81 @@
import { useNavigate } from "react-router-dom";
import MissionCard from "./MissionCard";
import { siteConfig } from "../config/navbarHero";

export default function MissionSection() {
const navigate = useNavigate();

const handleJoinUs = () => {
navigate("/applications");
};

return (
<section id="cards" className="w-full bg-white py-20 flex justify-center">
<div className="w-full max-w-none mx-auto grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 max-[1250px]:px-6 gap-14 place-items-center">
{siteConfig.missions.map(({ title, description }, index) => (
<MissionCard key={index} title={title} description={description} />
))}
<section
id="cards"
className="w-full bg-white py-20 relative overflow-hidden"
>
{/* Subtle Background Elements */}
<div className="absolute inset-0 overflow-hidden">
<div className="absolute top-20 right-10 w-72 h-72 bg-blue-50 rounded-full opacity-40 blur-2xl"></div>
<div className="absolute bottom-20 left-10 w-72 h-72 bg-indigo-50 rounded-full opacity-40 blur-2xl"></div>
</div>

<div className="relative z-10 max-w-7xl mx-auto px-6 lg:px-8">
{/* Section Header */}
<div className="text-center mb-16">
<h2 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6 leading-tight">
Driving Innovation Forward
</h2>
<p className="text-lg text-gray-600 max-w-3xl mx-auto leading-relaxed">
Discover the core values and principles that guide our engineering
community toward innovation, collaboration, and excellence in
technology.
</p>
</div>

{/* Mission Cards Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{siteConfig.missions.map(({ title, description }, index) => (
<div key={index} className="flex justify-center">
<MissionCard
title={title}
description={description}
index={index}
/>
</div>
))}
</div>

{/* Bottom CTA Section - Matching Card Colors */}
<div className="text-center mt-20">
<div className="relative bg-[#ffffff] text-white rounded-2xl p-10 shadow-lg border-2 border-gray-800">
{/* Decorative Elements - White with opacity */}
<div className="absolute top-4 right-4 w-16 h-16 bg-white/10 rounded-full opacity-50"></div>
<div className="absolute bottom-4 left-4 w-12 h-12 bg-white/5 rounded-full opacity-50"></div>

<div className="absolute inset-0 opacity-5 bg-gradient-to-r from-white/10 to-transparent rounded-2xl"></div>
<div className="absolute top-0 right-0 w-32 h-32 bg-white/5 rounded-full -translate-y-16 translate-x-16"></div>

<div className="relative z-10">
<h3 className="text-3xl font-bold text-[#0A1440] mb-4">
Ready to Join Our Mission?
</h3>
<p className="text-[#0A1440] mb-8 text-base leading-relaxed max-w-2xl mx-auto">
Be part of a community that's shaping the future of technology
and innovation. Connect with like-minded engineers and make an
impact.
</p>
<div className="flex justify-center">
<button
onClick={handleJoinUs}
className="px-10 py-4 bg-[#0A1440] text-white font-semibold rounded-lg transition-all duration-200 shadow-lg hover:shadow-xl transform hover:scale-105"
>
Join Us
</button>
</div>
</div>
</div>
</div>
</div>
</section>
);
Expand Down
Loading