1
1
"use client" ;
2
2
3
- import { motion } from "framer-motion " ;
4
- import { Terminal } from "lucide- react" ;
3
+ import { Play , Terminal } from "lucide-react " ;
4
+ import { motion } from "motion/ react" ;
5
5
import Image from "next/image" ;
6
6
import { Suspense } from "react" ;
7
7
import { Tweet , TweetSkeleton , type TwitterComponents } from "react-tweet" ;
8
8
9
+ const YOUTUBE_VIDEOS = [
10
+ {
11
+ id : "VIDEO_001" ,
12
+ embedId : "g-ynSAdL6Ak" ,
13
+ title : "This tool cured my JavaScript fatigue" ,
14
+ } ,
15
+ {
16
+ id : "VIDEO_002" ,
17
+ embedId : "uHUgw-Hi8HE" ,
18
+ title : "I tried React again after 2 years of Svelte" ,
19
+ } ,
20
+ ] ;
21
+
9
22
const TWEET_IDS = [
10
23
"1930194170418999437" ,
11
24
"1907728148294447538" ,
@@ -114,6 +127,45 @@ export default function Testimonials() {
114
127
} ,
115
128
} ;
116
129
130
+ const VideoCard = ( {
131
+ video,
132
+ index,
133
+ } : {
134
+ video : ( typeof YOUTUBE_VIDEOS ) [ 0 ] ;
135
+ index : number ;
136
+ } ) => (
137
+ < motion . div
138
+ className = "w-full min-w-0"
139
+ initial = { { opacity : 0 , y : 20 , scale : 0.95 } }
140
+ animate = { { opacity : 1 , y : 0 , scale : 1 } }
141
+ transition = { {
142
+ delay : index * 0.1 ,
143
+ duration : 0.4 ,
144
+ ease : "easeOut" ,
145
+ } }
146
+ >
147
+ < div className = "w-full min-w-0 overflow-hidden rounded border border-border" >
148
+ < div className = "sticky top-0 z-10 border-border border-b px-3 py-2" >
149
+ < div className = "flex items-center gap-2" >
150
+ < Play className = "h-3 w-3 text-primary" />
151
+ < span className = "font-semibold text-xs" > [{ video . id } ]</ span >
152
+ </ div >
153
+ </ div >
154
+ < div className = "w-full min-w-0 overflow-hidden" >
155
+ < div className = "relative aspect-video w-full" >
156
+ < iframe
157
+ src = { `https://www.youtube.com/embed/${ video . embedId } ` }
158
+ title = { video . title }
159
+ allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
160
+ allowFullScreen
161
+ className = "absolute inset-0 h-full w-full"
162
+ />
163
+ </ div >
164
+ </ div >
165
+ </ div >
166
+ </ motion . div >
167
+ ) ;
168
+
117
169
const TweetCard = ( {
118
170
tweetId,
119
171
index,
@@ -135,7 +187,7 @@ export default function Testimonials() {
135
187
< div className = "sticky top-0 z-10 border-border border-b px-3 py-2" >
136
188
< div className = "flex items-center gap-2" >
137
189
< span className = "text-primary text-xs" > ▶</ span >
138
- < span className = " font-semibold text-xs" >
190
+ < span className = "font-semibold text-xs" >
139
191
[TWEET_{ String ( index + 1 ) . padStart ( 3 , "0" ) } ]
140
192
</ span >
141
193
</ div >
@@ -153,6 +205,47 @@ export default function Testimonials() {
153
205
154
206
return (
155
207
< div className = "mb-12 w-full max-w-full overflow-hidden px-4" >
208
+ < div className = "mb-8" >
209
+ < div className = "mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap" >
210
+ < div className = "flex items-center gap-2" >
211
+ < Play className = "h-5 w-5 text-primary" />
212
+ < span className = "font-bold text-lg sm:text-xl" >
213
+ VIDEO_TESTIMONIALS.LOG
214
+ </ span >
215
+ </ div >
216
+ < div className = "hidden h-px flex-1 bg-border sm:block" />
217
+ < span className = "w-full text-right text-muted-foreground text-xs sm:w-auto sm:text-left" >
218
+ [{ YOUTUBE_VIDEOS . length } ENTRIES]
219
+ </ span >
220
+ </ div >
221
+
222
+ < div className = "block sm:hidden" >
223
+ < motion . div
224
+ className = "flex flex-col gap-4"
225
+ variants = { containerVariants }
226
+ initial = "hidden"
227
+ animate = "visible"
228
+ >
229
+ { YOUTUBE_VIDEOS . map ( ( video , index ) => (
230
+ < VideoCard key = { video . id } video = { video } index = { index } />
231
+ ) ) }
232
+ </ motion . div >
233
+ </ div >
234
+
235
+ < div className = "hidden sm:block" >
236
+ < motion . div
237
+ className = "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3"
238
+ variants = { containerVariants }
239
+ initial = "hidden"
240
+ animate = "visible"
241
+ >
242
+ { YOUTUBE_VIDEOS . map ( ( video , index ) => (
243
+ < VideoCard key = { video . id } video = { video } index = { index } />
244
+ ) ) }
245
+ </ motion . div >
246
+ </ div >
247
+ </ div >
248
+
156
249
< div className = "mb-6 flex flex-wrap items-center justify-between gap-2 sm:flex-nowrap" >
157
250
< div className = "flex items-center gap-2" >
158
251
< Terminal className = "h-5 w-5 text-primary" />
0 commit comments