11"use client" ;
2- import React from "react" ;
3- import { motion } from "framer-motion" ;
2+ import React , { useState } from "react" ;
3+ import { motion , AnimatePresence } from "framer-motion" ;
44import ProjectCard from "./ProjectCard" ;
55import projects from "../constants/projects" ;
66
7+ type AppType = "mobile" | "desktop" ;
8+
79const PersonalProjects : React . FC = ( ) => {
10+ const [ selectedType , setSelectedType ] = useState < AppType > ( "mobile" ) ;
11+
812 const personalProjects = projects . filter (
9- ( project ) => project . isPersonalProject
13+ ( project ) => project . isPersonalProject //&& project.type === selectedType
1014 ) ;
1115
1216 if ( personalProjects . length === 0 ) return null ;
@@ -20,22 +24,76 @@ const PersonalProjects: React.FC = () => {
2024 transition = { { duration : 0.5 } }
2125 className = "mb-6"
2226 >
23- < h2 className = "text-2xl sm:text-3xl font-bold text-gray-100 mb-0.5" >
24- Personal Projects
25- </ h2 >
26- < p className = "text-gray-400" > Actively working to improve them.</ p >
27- </ motion . div >
27+ < div className = "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6" >
28+ < div >
29+ < h2 className = "text-2xl sm:text-3xl font-bold text-gray-100 mb-0.5" >
30+ Personal Projects
31+ </ h2 >
32+ < p className = "text-gray-400" > Actively evolving</ p >
33+ </ div >
2834
29- < motion . div
30- initial = { { opacity : 0 } }
31- animate = { { opacity : 1 } }
32- transition = { { duration : 0.5 , delay : 0.2 } }
33- className = "grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6"
34- >
35- { personalProjects . map ( ( project , index ) => (
36- < ProjectCard key = { project . name } project = { project } index = { index } />
37- ) ) }
35+ { /* Toggle Switch */ }
36+ < div className = "flex items-center bg-gray-900/80 rounded-full p-1.5 border border-gray-700/50" >
37+ < button
38+ onClick = { ( ) => setSelectedType ( "mobile" ) }
39+ className = { `relative px-4 py-1.5 rounded-full text-sm font-medium transition-all duration-200 ${
40+ selectedType === "mobile"
41+ ? "text-gray-900 shadow-sm"
42+ : "text-gray-300 hover:text-gray-100"
43+ } `}
44+ >
45+ < span className = "relative z-10" > Mobile Apps</ span >
46+ { selectedType === "mobile" && (
47+ < motion . div
48+ layoutId = "pill"
49+ className = "absolute inset-0 bg-gradient-to-r from-blue-400 to-blue-500 rounded-full -z-0 shadow-lg shadow-blue-500/20"
50+ transition = { {
51+ type : "spring" ,
52+ duration : 0.5 ,
53+ bounce : 0.15 ,
54+ } }
55+ />
56+ ) }
57+ </ button >
58+ < button
59+ onClick = { ( ) => setSelectedType ( "desktop" ) }
60+ className = { `relative px-4 py-1.5 rounded-full text-sm font-medium transition-all duration-200 ${
61+ selectedType === "desktop"
62+ ? "text-gray-900 shadow-sm"
63+ : "text-gray-300 hover:text-gray-100"
64+ } `}
65+ >
66+ < span className = "relative z-10" > Desktop</ span >
67+ { selectedType === "desktop" && (
68+ < motion . div
69+ layoutId = "pill"
70+ className = "absolute inset-0 bg-gradient-to-r from-blue-400 to-blue-500 rounded-full -z-0 shadow-lg shadow-blue-500/20"
71+ transition = { {
72+ type : "spring" ,
73+ duration : 0.5 ,
74+ bounce : 0.15 ,
75+ } }
76+ />
77+ ) }
78+ </ button >
79+ </ div >
80+ </ div >
3881 </ motion . div >
82+
83+ < AnimatePresence mode = "wait" >
84+ < motion . div
85+ key = { selectedType }
86+ initial = { { opacity : 0 , y : 20 } }
87+ animate = { { opacity : 1 , y : 0 } }
88+ exit = { { opacity : 0 , y : - 20 } }
89+ transition = { { duration : 0.3 } }
90+ className = "grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6"
91+ >
92+ { personalProjects . map ( ( project , index ) => (
93+ < ProjectCard key = { project . name } project = { project } index = { index } />
94+ ) ) }
95+ </ motion . div >
96+ </ AnimatePresence >
3997 </ div >
4098 </ section >
4199 ) ;
0 commit comments