11"use client" ;
2- import React from "react" ;
2+ import React , { useState } from "react" ;
33import ProjectCard from "./ProjectCard" ;
44import projects , { Project } from "../constants/projects" ;
5- import { motion } from "framer-motion" ;
5+ import { motion , AnimatePresence } from "framer-motion" ;
66
77const Projects = ( ) => {
8- // Group projects by year (assuming you'll add year to your project data)
8+ const [ showAll , setShowAll ] = useState ( false ) ;
9+
10+ // Group projects by year
911 const projectsByYear = projects . reduce (
1012 ( acc : { [ key : string ] : Project [ ] } , project ) => {
11- const year = project . year || 2023 ; // Default to 2023 if year is not specified
13+ const year = project . year || 2023 ;
1214 if ( ! acc [ year ] ) {
1315 acc [ year ] = [ ] ;
1416 }
@@ -23,6 +25,11 @@ const Projects = () => {
2325 ( a : string , b : string ) => parseInt ( b ) - parseInt ( a )
2426 ) ;
2527
28+ // Get visible years based on showAll state
29+ const visibleYears = showAll ? sortedYears : sortedYears . slice ( 0 , 1 ) ; // Show first 2 years by default
30+
31+ const hasMoreYears = sortedYears . length > 2 ;
32+
2633 return (
2734 < section className = "py-8 sm:py-16 px-3 sm:px-4 bg-gray-900" >
2835 < div className = "max-w-4xl mx-auto" >
@@ -35,37 +42,94 @@ const Projects = () => {
3542 Project Timeline
3643 </ motion . h2 >
3744
38- < div className = "space-y-12 sm:space-y-16" >
39- { sortedYears . map ( ( year , yearIndex ) => (
40- < motion . div
41- key = { year }
42- initial = { { opacity : 0 , x : - 20 } }
43- animate = { { opacity : 1 , x : 0 } }
44- transition = { { duration : 0.5 , delay : yearIndex * 0.2 } }
45- className = "relative"
46- >
47- { /* Year Label */ }
45+ < AnimatePresence mode = "wait" >
46+ < div className = "space-y-12 sm:space-y-16" >
47+ { visibleYears . map ( ( year , yearIndex ) => (
4848 < motion . div
49- className = "flex items-center mb-6 sm:mb-8"
50- initial = { { width : 0 } }
51- animate = { { width : "100%" } }
52- transition = { { duration : 0.8 , delay : yearIndex * 0.2 + 0.3 } }
49+ key = { year }
50+ initial = { { opacity : 0 , x : - 20 } }
51+ animate = { { opacity : 1 , x : 0 } }
52+ transition = { { duration : 0.5 , delay : yearIndex * 0.2 } }
53+ className = "relative"
5354 >
54- < div className = "w-12 h-12 sm:w-16 sm:h-16 rounded-full bg-blue-600 flex items-center justify-center text-xl sm:text-2xl font-bold text-white" >
55- { year }
55+ { /* Year Label */ }
56+ < motion . div
57+ className = "flex items-center mb-6 sm:mb-8"
58+ initial = { { width : 0 } }
59+ animate = { { width : "100%" } }
60+ transition = { { duration : 0.8 , delay : yearIndex * 0.2 + 0.3 } }
61+ >
62+ < div className = "w-12 h-12 sm:w-16 sm:h-16 rounded-full bg-blue-600 flex items-center justify-center text-xl sm:text-2xl font-bold text-white" >
63+ { year }
64+ </ div >
65+ < div className = "h-0.5 flex-1 bg-blue-600 ml-3 sm:ml-4" > </ div >
66+ </ motion . div >
67+
68+ { /* Projects Grid */ }
69+ < div className = "grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6" >
70+ { projectsByYear [ year ] . map ( ( project , index ) => (
71+ < ProjectCard
72+ key = { project . name }
73+ project = { project }
74+ index = { index }
75+ />
76+ ) ) }
5677 </ div >
57- < div className = "h-0.5 flex-1 bg-blue-600 ml-3 sm:ml-4" > </ div >
5878 </ motion . div >
79+ ) ) }
80+ </ div >
81+ </ AnimatePresence >
5982
60- { /* Projects Grid */ }
61- < div className = "grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6" >
62- { projectsByYear [ year ] . map ( ( project , index ) => (
63- < ProjectCard key = { index } project = { project } index = { index } />
64- ) ) }
65- </ div >
66- </ motion . div >
67- ) ) }
68- </ div >
83+ { /* Show More Button */ }
84+ { hasMoreYears && (
85+ < motion . div
86+ initial = { { opacity : 0 } }
87+ animate = { { opacity : 1 } }
88+ transition = { { delay : 0.3 } }
89+ className = "mt-12 flex justify-center"
90+ >
91+ < motion . button
92+ onClick = { ( ) => setShowAll ( ! showAll ) }
93+ className = "group relative px-6 py-2 text-sm font-medium text-gray-300 hover:text-white transition-colors"
94+ whileHover = { { scale : 1.05 } }
95+ whileTap = { { scale : 0.95 } }
96+ >
97+ < span className = "relative z-10" >
98+ { showAll
99+ ? "Show Less"
100+ : `Show ${ sortedYears . length - 2 } More Years` }
101+ </ span >
102+ < motion . div
103+ className = "absolute inset-0 bg-gradient-to-r from-blue-600/20 to-blue-500/20 rounded-full -z-0"
104+ whileHover = { {
105+ scale : 1.05 ,
106+ background :
107+ "linear-gradient(to right, rgba(37, 99, 235, 0.3), rgba(59, 130, 246, 0.3))" ,
108+ } }
109+ />
110+ < motion . div
111+ className = "absolute inset-0 border border-blue-500/50 rounded-full"
112+ initial = { { scale : 1 } }
113+ whileHover = { { scale : 1.05 } }
114+ />
115+
116+ { /* Animated Arrow */ }
117+ < motion . svg
118+ className = { `w-4 h-4 ml-2 inline-block transition-transform duration-200 ${
119+ showAll ? "rotate-180" : ""
120+ } `}
121+ viewBox = "0 0 24 24"
122+ fill = "none"
123+ stroke = "currentColor"
124+ strokeWidth = "2"
125+ strokeLinecap = "round"
126+ strokeLinejoin = "round"
127+ >
128+ < polyline points = "6 9 12 15 18 9" />
129+ </ motion . svg >
130+ </ motion . button >
131+ </ motion . div >
132+ ) }
69133 </ div >
70134 </ section >
71135 ) ;
0 commit comments