feat: add AboutSummary component with personal introduction and game preview
feat: create Chip component for displaying technology tags feat: implement ExperienceCard component to showcase job experiences feat: add Experience component to list multiple job experiences feat: create Footer component with social links and copyright information feat: implement Hero component for the landing section with social links feat: add ImageCarousel component for displaying project images feat: create Navbar component with scroll effect and navigation links feat: implement ProjectItem component to display individual project details feat: add Skills component to showcase technical skills feat: create data module with skills, jobs, and projects information feat: define types for Skill, Job, and Project in types module chore: update package.json with new dependencies for Tailwind CSS and Lucide icons chore: add CV PDF file to public directory chore: remove unused SVG files from public directory chore: add new images for background and hero sections feat: implement formatDate utility function for date formatting
This commit is contained in:
60
components/image-carousel.tsx
Normal file
60
components/image-carousel.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
interface ImageCarouselProps {
|
||||
id: string;
|
||||
thumbnails: string[];
|
||||
}
|
||||
|
||||
const ImageCarousel = ({ id, thumbnails }: ImageCarouselProps) => {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
const goToSlide = (slideIndex: number) => {
|
||||
setCurrentIndex(slideIndex);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
id={id}
|
||||
className="carousel relative shadow-lg w-full max-w-full md:max-w-[50hw] h-[40rem]"
|
||||
>
|
||||
<div className="relative w-full h-full overflow-hidden carousel-inner">
|
||||
{thumbnails.map((thumbnail, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`absolute inset-0 w-full h-full transition-opacity duration-500 ease-in-out delay-250 ${
|
||||
currentIndex === index ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
>
|
||||
<Image
|
||||
alt={`Slide ${index + 1}`}
|
||||
src={thumbnail}
|
||||
fill
|
||||
style={{ objectFit: "scale-down" }}
|
||||
priority={index === 0}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-0 z-10 flex justify-center w-full gap-2 py-2">
|
||||
{thumbnails.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => goToSlide(index)}
|
||||
className={`text-2xl leading-none ${
|
||||
currentIndex === index ? "text-white" : "text-white/50"
|
||||
}`}
|
||||
aria-label={`Go to slide ${index + 1}`}
|
||||
>
|
||||
•
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageCarousel;
|
Reference in New Issue
Block a user