1
+ /* eslint-disable linebreak-style */
1
2
import React , { useState } from 'react' ;
2
3
import Image from 'next/image' ;
4
+ import {
5
+ Card ,
6
+ CardContent ,
7
+ CardHeader ,
8
+ CardTitle ,
9
+ CardDescription ,
10
+ } from '@/components/ui/card' ;
11
+ import { Button } from '@/components/ui/button' ;
3
12
4
13
interface Contribution {
5
14
title : string ;
@@ -105,14 +114,7 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => {
105
114
ambassador . img || '/api/placeholder/400/320' ,
106
115
) ;
107
116
108
- const {
109
- name = 'Ambassador' ,
110
- title,
111
- bio,
112
- company,
113
- country,
114
- contributions = [ ] ,
115
- } = ambassador ;
117
+ const { name, title, bio, company, country, contributions = [ ] } = ambassador ;
116
118
117
119
const SocialIcons : SocialIcons [ ] = [
118
120
'github' ,
@@ -122,33 +124,45 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => {
122
124
] ;
123
125
124
126
return (
125
- < div className = 'relative flex flex-col max-w-sm md:max-w-md lg:max-w-lg mx-auto bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden my-4 h-full' >
126
- < div className = 'absolute top-0 right-0 w-1 h-20 bg-black dark:bg-gray-400' > </ div >
127
- < div className = 'absolute bottom-100 right-0 w-20 h-1 bg-black dark:bg-gray-400' > </ div >
128
- < div className = 'absolute bottom-0 left-0 w-1 h-20 bg-black dark:bg-gray-400' > </ div >
129
- < div className = 'absolute bottom-0 left-0 w-20 h-1 bg-black dark:bg-gray-400' > </ div >
130
-
131
- < Image
132
- className = 'w-full object-cover p-5 rounded-3xl'
133
- src = { imgSrc }
134
- alt = { `${ name } profile` }
135
- width = { 400 }
136
- height = { 320 }
137
- onError = { ( ) => setImgSrc ( `/img/ambassadors/${ name } .jpg` ) }
138
- />
139
-
140
- < div className = 'flex flex-col flex-grow p-6' >
141
- < h3 className = 'text-xl font-semibold mb-2 text-gray-900 dark:text-white' >
142
- { name }
143
- </ h3 >
144
- { title && (
145
- < p className = 'text-gray-500 dark:text-slate-100 mb-1' > { title } </ p >
146
- ) }
127
+ < Card className = 'py-0 relative max-w-md md:max-w-lg lg:max-w-xl mx-auto bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden my-4 h-full border-0' >
128
+ { /* Decorative corner elements */ }
129
+ < div className = 'absolute top-0 right-0 w-1 h-20 bg-gray-400' > </ div >
130
+ < div className = 'absolute top-0 right-0 w-20 h-1 bg-gray-400' > </ div >
131
+ < div className = 'absolute bottom-0 left-0 w-1 h-20 bg-gray-400' > </ div >
132
+ < div className = 'absolute bottom-0 left-0 w-20 h-1 bg-gray-400' > </ div >
133
+
134
+ { /* Image section */ }
135
+ < div className = 'p-5' >
136
+ < div className = 'w-full h-80 relative overflow-hidden rounded-2xl' >
137
+ < Image
138
+ className = 'w-full h-full object-cover'
139
+ src = { imgSrc }
140
+ alt = { `${ name } profile` }
141
+ fill
142
+ sizes = '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
143
+ onError = { ( ) => setImgSrc ( `/img/ambassadors/${ name } .jpg` ) }
144
+ />
145
+ </ div >
146
+ </ div >
147
+
148
+ < CardContent className = 'flex flex-col flex-grow p-6 pt-0' >
149
+ < CardHeader className = 'p-0 mb-4' >
150
+ < CardTitle className = 'text-xl font-semibold mb-2 text-gray-900 dark:text-white' >
151
+ { name }
152
+ </ CardTitle >
153
+ { title && (
154
+ < CardDescription className = 'text-gray-500 dark:text-slate-100 mb-1' >
155
+ { title }
156
+ </ CardDescription >
157
+ ) }
158
+ </ CardHeader >
159
+
147
160
{ bio && (
148
161
< p className = 'text-gray-700 dark:text-slate-100 text-sm mb-4' >
149
162
{ bio }
150
163
</ p >
151
164
) }
165
+
152
166
{ ( company || country ) && (
153
167
< p className = 'text-gray-500 dark:text-slate-100 mb-4' >
154
168
{ company }
@@ -157,6 +171,7 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => {
157
171
</ p >
158
172
) }
159
173
174
+ { /* Social icons */ }
160
175
< div className = 'flex justify-center mb-4 mt-auto' >
161
176
{ SocialIcons . map ( ( platform ) => {
162
177
const username = ambassador [ platform ] ;
@@ -175,44 +190,65 @@ const AmbassadorCard = ({ ambassador }: { ambassador: Ambassador }) => {
175
190
} ) }
176
191
</ div >
177
192
193
+ { /* Contributions button */ }
178
194
{ contributions . length > 0 && (
179
- < button
195
+ < Button
180
196
onClick = { ( ) => setShowContributions ( ! showContributions ) }
181
197
className = { `w-full bg-blue-600 dark:bg-blue-500 hover:bg-blue-700 dark:hover:bg-blue-400 text-white dark:text-slate-100 font-semibold py-2 px-4 rounded transition-all duration-300 transform ${
182
- showContributions ? 'rotate' : ''
198
+ showContributions
199
+ ? 'scale-105 shadow-lg shadow-blue-500/50'
200
+ : 'scale-100 shadow-md'
183
201
} `}
202
+ variant = 'default'
184
203
>
185
204
{ showContributions ? 'Hide Details' : 'Show Full Details' }
186
- </ button >
205
+ </ Button >
187
206
) }
188
207
189
- { showContributions && contributions . length > 0 && (
190
- < div className = 'mt-4' >
191
- < h4 className = 'text-lg font-semibold mb-2 text-gray-900 dark:text-white' >
192
- Contributions
193
- </ h4 >
194
- < ul className = 'text-gray-600 dark:text-slate-100 text-sm' >
195
- { contributions . map ( ( contribution , index ) => (
196
- < li key = { index } className = 'mb-2' >
197
- < strong > { contribution . title } </ strong >
198
- { contribution . date &&
199
- ` (${ contribution . date . month } ${ contribution . date . year } )` } { ' ' }
200
- -
201
- < a
202
- href = { contribution . link }
203
- className = 'text-blue-600 dark:text-blue-400 ml-1 hover:underline'
204
- target = '_blank'
205
- rel = 'noopener noreferrer'
208
+ { /* Contributions list with animation */ }
209
+ < div
210
+ className = { `overflow-hidden transition-all duration-500 ease-in-out ${
211
+ showContributions ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
212
+ } `}
213
+ >
214
+ { contributions . length > 0 && (
215
+ < div className = 'mt-4 pt-4 border-t border-gray-200 dark:border-gray-700' >
216
+ < h4 className = 'text-lg font-semibold mb-2 text-gray-900 dark:text-white' >
217
+ Contributions
218
+ </ h4 >
219
+ < ul className = 'text-gray-600 dark:text-slate-100 text-sm space-y-2' >
220
+ { contributions . map ( ( contribution , index ) => (
221
+ < li
222
+ key = { index }
223
+ className = { `transform transition-all duration-300 ease-out ${
224
+ showContributions
225
+ ? 'translate-y-0 opacity-100'
226
+ : 'translate-y-4 opacity-0'
227
+ } `}
228
+ style = { {
229
+ transitionDelay : `${ index * 100 } ms` ,
230
+ } }
206
231
>
207
- { contribution . type }
208
- </ a >
209
- </ li >
210
- ) ) }
211
- </ ul >
212
- </ div >
213
- ) }
214
- </ div >
215
- </ div >
232
+ < strong > { contribution . title } </ strong >
233
+ { contribution . date &&
234
+ ` (${ contribution . date . month } ${ contribution . date . year } )` } { ' ' }
235
+ -
236
+ < a
237
+ href = { contribution . link }
238
+ className = 'text-blue-600 dark:text-blue-400 ml-1 hover:underline transition-colors duration-200'
239
+ target = '_blank'
240
+ rel = 'noopener noreferrer'
241
+ >
242
+ { contribution . type }
243
+ </ a >
244
+ </ li >
245
+ ) ) }
246
+ </ ul >
247
+ </ div >
248
+ ) }
249
+ </ div >
250
+ </ CardContent >
251
+ </ Card >
216
252
) ;
217
253
} ;
218
254
0 commit comments