@@ -88,7 +88,7 @@ export default function BlogPostPage() {
8888 const [ likedByUser , setLikedByUser ] = useState ( false ) ;
8989 const [ views , setViews ] = useState < number > ( 0 ) ;
9090 const params = useParams ( )
91-
91+
9292 const slug = params ?. slug as string
9393
9494 useEffect ( ( ) => {
@@ -115,8 +115,8 @@ export default function BlogPostPage() {
115115 tags : Array . isArray ( data . tags )
116116 ? data . tags
117117 : ( typeof data . tags === 'string' && data . tags
118- ? ( data . tags as string ) . split ( ',' ) . map ( ( t : string ) => t . trim ( ) )
119- : [ ] ) ,
118+ ? ( data . tags as string ) . split ( ',' ) . map ( ( t : string ) => t . trim ( ) )
119+ : [ ] ) ,
120120 } )
121121 }
122122 setIsLoading ( false )
@@ -195,19 +195,97 @@ export default function BlogPostPage() {
195195
196196 if ( isLoading ) {
197197 return (
198- < div className = "min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted/20" >
199- < div className = "relative" >
200- < div className = "animate-spin rounded-full h-12 w-12 border-4 border-primary border-t-transparent" > </ div >
201- < div className = "absolute inset-0 rounded-full border-4 border-primary/20 animate-ping" > </ div >
202- </ div >
198+ < div className = "min-h-screen bg-gradient-to-br from-background via-background to-muted/20" >
199+ < Header />
200+ < header className = "border-b bg-background/80 backdrop-blur-sm sticky top-0 z-50 shadow-lg" >
201+ < div className = "container px-4 mx-auto py-4" >
202+ < div className = "flex items-center justify-between" >
203+ < div className = "h-9 w-32 bg-muted/50 rounded-md animate-pulse relative overflow-hidden" >
204+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
205+ </ div >
206+ < div className = "flex items-center space-x-4" >
207+ < div className = "h-9 w-24 bg-muted/50 rounded-md animate-pulse relative overflow-hidden" >
208+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
209+ </ div >
210+ < div className = "h-9 w-16 bg-muted/50 rounded-md animate-pulse relative overflow-hidden" >
211+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
212+ </ div >
213+ </ div >
214+ </ div >
215+ </ div >
216+ </ header >
217+
218+ < article className = "container px-4 mx-auto py-12" >
219+ < div className = "max-w-4xl mx-auto" >
220+ { /* article header skeleton */ }
221+ < div className = "space-y-6 mb-12" >
222+ < div className = "flex items-center space-x-4" >
223+ < div className = "h-6 w-24 bg-muted/50 rounded-full animate-pulse relative overflow-hidden" >
224+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
225+ </ div >
226+ </ div >
227+
228+ < div className = "space-y-4" >
229+ < div className = "h-12 w-3/4 bg-muted/50 rounded-lg animate-pulse relative overflow-hidden" >
230+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
231+ </ div >
232+ < div className = "h-12 w-1/2 bg-muted/50 rounded-lg animate-pulse relative overflow-hidden" >
233+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
234+ </ div >
235+ </ div >
236+
237+ < div className = "space-y-3" >
238+ < div className = "h-6 w-full bg-muted/30 rounded animate-pulse relative overflow-hidden" >
239+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
240+ </ div >
241+ < div className = "h-6 w-5/6 bg-muted/30 rounded animate-pulse relative overflow-hidden" >
242+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
243+ </ div >
244+ </ div >
245+
246+ < div className = "flex flex-wrap items-center gap-6 pt-4" >
247+ { [ 1 , 2 , 3 , 4 , 5 ] . map ( ( i ) => (
248+ < div key = { i } className = "h-8 w-24 bg-muted/50 rounded-full animate-pulse relative overflow-hidden" style = { { animationDelay : `${ i * 100 } ms` } } >
249+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" style = { { animationDelay : `${ i * 100 } ms` } } />
250+ </ div >
251+ ) ) }
252+ </ div >
253+ </ div >
254+
255+ { /* article image skeleton */ }
256+ < div className = "mb-12" >
257+ < div className = "aspect-[1280/1080] bg-muted/50 rounded-2xl animate-pulse relative overflow-hidden" >
258+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
259+ </ div >
260+ </ div >
261+
262+ { /* article content skeleton */ }
263+ < div className = "space-y-6" >
264+ { [ 1 , 2 , 3 , 4 ] . map ( ( i ) => (
265+ < div key = { i } className = "space-y-3" style = { { animationDelay : `${ i * 150 } ms` } } >
266+ < div className = "h-4 w-full bg-muted/40 rounded animate-pulse relative overflow-hidden" >
267+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" style = { { animationDelay : `${ i * 150 } ms` } } />
268+ </ div >
269+ < div className = "h-4 w-full bg-muted/40 rounded animate-pulse relative overflow-hidden" >
270+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" style = { { animationDelay : `${ i * 150 + 50 } ms` } } />
271+ </ div >
272+ < div className = "h-4 w-3/4 bg-muted/40 rounded animate-pulse relative overflow-hidden" >
273+ < div className = "absolute inset-0 -translate-x-full animate-[shimmer_1.5s_infinite] bg-gradient-to-r from-transparent via-white/10 to-transparent" style = { { animationDelay : `${ i * 150 + 100 } ms` } } />
274+ </ div >
275+ </ div >
276+ ) ) }
277+ </ div >
278+ </ div >
279+ </ article >
280+ < Footer />
203281 </ div >
204282 )
205283 }
206284
207285 if ( fetchError ) {
208286 return (
209287 < div className = "min-h-screen flex items-center justify-center bg-gradient-to-br from-background via-background to-muted/20" >
210- < motion . div
288+ < motion . div
211289 className = "text-center space-y-4"
212290 initial = { { opacity : 0 , scale : 0.9 } }
213291 animate = { { opacity : 1 , scale : 1 } }
@@ -232,7 +310,7 @@ export default function BlogPostPage() {
232310 return (
233311 < div className = "min-h-screen bg-gradient-to-br from-background via-background to-muted/20" >
234312 { /* header */ }
235- < Header />
313+ < Header />
236314 < header className = "border-b bg-background/80 backdrop-blur-sm sticky top-0 z-50 shadow-lg" >
237315 < div className = "container px-4 mx-auto py-4" >
238316 < div className = "flex items-center justify-between" >
@@ -248,13 +326,13 @@ export default function BlogPostPage() {
248326 </ Link >
249327 </ Button >
250328 </ motion . div >
251- < motion . div
329+ < motion . div
252330 className = "flex items-center space-x-4"
253331 initial = { { opacity : 0 , x : 20 } }
254332 animate = { { opacity : 1 , x : 0 } }
255333 transition = { { duration : 0.3 , delay : 0.1 } }
256334 >
257- < ShareButton
335+ < ShareButton
258336 url = { `${ process . env . NEXT_PUBLIC_SITE_URL || 'http://localhost:3000' } /blog/${ slug } ` }
259337 title = { post ?. title || '' }
260338 description = { post ?. excerpt || '' }
@@ -270,7 +348,7 @@ export default function BlogPostPage() {
270348 < article className = "container px-4 mx-auto py-12" >
271349 < div className = "max-w-4xl mx-auto" >
272350 { /* article header */ }
273- < motion . div
351+ < motion . div
274352 initial = { { opacity : 0 , y : 20 } }
275353 animate = { { opacity : 1 , y : 0 } }
276354 transition = { { duration : 0.5 } }
@@ -286,26 +364,26 @@ export default function BlogPostPage() {
286364 </ Badge >
287365 ) }
288366 </ div >
289-
367+
290368 < h1 className = "text-4xl md:text-5xl lg:text-6xl font-bold leading-tight bg-gradient-to-r from-foreground via-foreground to-muted-foreground bg-clip-text text-transparent" >
291369 { post ?. title }
292370 </ h1 >
293-
371+
294372 < p className = "text-xl md:text-2xl text-muted-foreground leading-relaxed" >
295373 { post ?. excerpt }
296374 </ p >
297-
375+
298376 < div className = "flex flex-wrap items-center gap-6 text-sm text-muted-foreground" >
299377 < div className = "flex items-center space-x-2 bg-background/80 backdrop-blur-sm px-3 py-2 rounded-full" >
300378 < User className = "h-4 w-4" />
301379 < span > { post ?. author } </ span >
302380 </ div >
303381 < div className = "flex items-center space-x-2 bg-background/80 backdrop-blur-sm px-3 py-2 rounded-full" >
304382 < Calendar className = "h-4 w-4" />
305- < span > { new Date ( post ?. date || '' ) . toLocaleDateString ( 'en-US' , {
306- year : 'numeric' ,
307- month : 'long' ,
308- day : 'numeric'
383+ < span > { new Date ( post ?. date || '' ) . toLocaleDateString ( 'en-US' , {
384+ year : 'numeric' ,
385+ month : 'long' ,
386+ day : 'numeric'
309387 } ) } </ span >
310388 </ div >
311389 < div className = "flex items-center space-x-2 bg-background/80 backdrop-blur-sm px-3 py-2 rounded-full" >
@@ -324,7 +402,7 @@ export default function BlogPostPage() {
324402 </ motion . div >
325403
326404 { /* article image */ }
327- < motion . div
405+ < motion . div
328406 initial = { { opacity : 0 , scale : 0.95 } }
329407 animate = { { opacity : 1 , scale : 1 } }
330408 transition = { { duration : 0.5 , delay : 0.2 } }
@@ -355,7 +433,7 @@ export default function BlogPostPage() {
355433 </ motion . div >
356434
357435 { /* article content */ }
358- < motion . div
436+ < motion . div
359437 initial = { { opacity : 0 , y : 20 } }
360438 animate = { { opacity : 1 , y : 0 } }
361439 transition = { { duration : 0.5 , delay : 0.3 } }
@@ -369,7 +447,7 @@ export default function BlogPostPage() {
369447 { post ?. content }
370448 </ ReactMarkdown >
371449 </ div >
372-
450+
373451 { /* tags */ }
374452 < div className = "flex flex-wrap gap-2 pt-8 border-t border-primary/10" >
375453 { post ?. tags . map ( ( tag : string ) => (
@@ -387,7 +465,7 @@ export default function BlogPostPage() {
387465 { post ?. content . split ( '\n\n' ) . slice ( 0 , 3 ) . join ( '\n\n' ) }
388466 </ ReactMarkdown >
389467 </ div >
390-
468+
391469 { /* authentication prompt */ }
392470 < motion . div
393471 initial = { { opacity : 0 , y : 20 } }
@@ -428,7 +506,7 @@ export default function BlogPostPage() {
428506 </ motion . div >
429507 </ div >
430508 </ article >
431- < Footer />
509+ < Footer />
432510 </ div >
433511 )
434512}
0 commit comments