1
1
"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" ;
4
4
import ProjectCard from "./ProjectCard" ;
5
5
import projects from "../constants/projects" ;
6
6
7
+ type AppType = "mobile" | "desktop" ;
8
+
7
9
const PersonalProjects : React . FC = ( ) => {
10
+ const [ selectedType , setSelectedType ] = useState < AppType > ( "mobile" ) ;
11
+
8
12
const personalProjects = projects . filter (
9
- ( project ) => project . isPersonalProject
13
+ ( project ) => project . isPersonalProject //&& project.type === selectedType
10
14
) ;
11
15
12
16
if ( personalProjects . length === 0 ) return null ;
@@ -20,22 +24,76 @@ const PersonalProjects: React.FC = () => {
20
24
transition = { { duration : 0.5 } }
21
25
className = "mb-6"
22
26
>
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 >
28
34
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 >
38
81
</ 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 >
39
97
</ div >
40
98
</ section >
41
99
) ;
0 commit comments