11import { useState , useEffect } from "react" ;
2- import { ExternalLink , Calendar , Clock } from "lucide-react" ;
2+ import { ExternalLink , Calendar } from "lucide-react" ;
33import { Button } from "@/components/ui/button" ;
4- import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card" ;
5- import { Badge } from "@/components/ui/badge" ;
64import { Skeleton } from "@/components/ui/skeleton" ;
75
86interface BlogPost {
@@ -13,14 +11,22 @@ interface BlogPost {
1311 thumbnail ?: string ;
1412}
1513
14+ interface RSSItem {
15+ title : string ;
16+ link : string ;
17+ pubDate : string ;
18+ description : string ;
19+ thumbnail ?: string ;
20+ }
21+
1622const Writing = ( ) => {
1723 const [ posts , setPosts ] = useState < BlogPost [ ] > ( [ ] ) ;
1824 const [ loading , setLoading ] = useState ( true ) ;
1925 const [ error , setError ] = useState < string | null > ( null ) ;
2026
2127 const formatDescription = ( htmlDescription : string ) : string => {
2228 // Remove HTML tags but preserve some structure
23- let text = htmlDescription
29+ const text = htmlDescription
2430 . replace ( / < \/ p > / g, '\n\n' ) // Convert closing p tags to double line breaks
2531 . replace ( / < \/ h [ 1 - 6 ] > / g, '\n\n' ) // Convert closing header tags to double line breaks
2632 . replace ( / < b r \s * \/ ? > / g, '\n' ) // Convert br tags to line breaks
@@ -62,7 +68,7 @@ const Writing = () => {
6268 const data = await response . json ( ) ;
6369
6470 if ( data . status === "ok" ) {
65- const formattedPosts = data . items . slice ( 0 , 6 ) . map ( ( item : any ) => ( {
71+ const formattedPosts = data . items . slice ( 0 , 6 ) . map ( ( item : RSSItem ) => ( {
6672 title : item . title ,
6773 link : item . link ,
6874 pubDate : item . pubDate ,
@@ -96,30 +102,36 @@ const Writing = () => {
96102
97103 if ( loading ) {
98104 return (
99- < div className = "max-w-6xl mx-auto space-y-8" >
105+ < div className = "mx-auto max-w-[1200px] px-4 md:px-6 space-y-8" >
100106 < div className = "text-center space-y-4" >
101107 < h1 className = "text-3xl md:text-4xl font-bold" > Writing</ h1 >
102108 < p className = "text-lg text-muted-foreground" > Loading latest posts...</ p >
103109 </ div >
104- < div className = "grid md:grid-cols-2 lg:grid-cols-3 gap-6 " >
110+ < div className = "grid gap-4 md:gap-6 grid-cols-1 sm:grid-cols- 2 lg:grid-cols-3 [grid-template-columns:repeat(auto-fit,minmax(320px,1fr))] " >
105111 { [ ...Array ( 6 ) ] . map ( ( _ , i ) => (
106- < Card key = { i } >
107- < CardHeader >
112+ < article
113+ key = { i }
114+ className = "flex flex-col rounded-xl border border-border bg-card p-6 shadow-sm"
115+ >
116+ < header className = "space-y-2" >
108117 < Skeleton className = "h-4 w-3/4" />
109118 < Skeleton className = "h-3 w-1/2" />
110- </ CardHeader >
111- < CardContent >
119+ </ header >
120+ < div className = "mt-3 grow" >
112121 < Skeleton className = "h-20 w-full" />
113- </ CardContent >
114- </ Card >
122+ </ div >
123+ < footer className = "mt-4" >
124+ < Skeleton className = "h-4 w-24" />
125+ </ footer >
126+ </ article >
115127 ) ) }
116128 </ div >
117129 </ div >
118130 ) ;
119131 }
120132
121133 return (
122- < div className = "max-w-6xl mx-auto space-y-8" >
134+ < div className = "mx-auto max-w-[1200px] px-4 md:px-6 space-y-8" >
123135 < div className = "text-center space-y-4" >
124136 < h1 className = "text-3xl md:text-4xl font-bold" > Writing</ h1 >
125137 < p className = "text-lg text-muted-foreground max-w-2xl mx-auto" >
@@ -142,30 +154,38 @@ const Writing = () => {
142154 </ Button >
143155 </ div >
144156
145- < div className = "grid md:grid-cols-2 lg:grid-cols-3 gap-6 " >
157+ < div className = "grid gap-4 md:gap-6 grid-cols-1 sm:grid-cols- 2 lg:grid-cols-3 [grid-template-columns:repeat(auto-fit,minmax(320px,1fr))] " >
146158 { posts . map ( ( post , index ) => (
147- < Card key = { index } className = "group hover:shadow-lg transition-shadow duration-200" >
148- < CardHeader className = "pb-3" >
149- < div className = "flex items-center space-x-2 text-sm text-muted-foreground mb-2" >
159+ < article
160+ key = { index }
161+ className = "group flex flex-col rounded-xl border border-border bg-card p-6 shadow-sm transition hover:-translate-y-0.5 hover:shadow-md focus-within:-translate-y-0.5 focus-within:shadow-md"
162+ >
163+ < header >
164+ < div className = "mb-2 flex items-center space-x-2 text-sm text-muted-foreground" >
150165 < Calendar className = "h-4 w-4" />
151166 < span > { formatDate ( post . pubDate ) } </ span >
152167 </ div >
153- < CardTitle className = "text-lg leading-tight group-hover:text-primary transition-colors" >
168+ < h3 className = "text-lg font-semibold leading-snug group-hover:text-primary transition-colors" >
154169 { post . title }
155- </ CardTitle >
156- </ CardHeader >
157- < CardContent className = "space-y-4 " >
170+ </ h3 >
171+ </ header >
172+ < div className = "mt-3 grow " >
158173 < p className = "text-sm text-muted-foreground whitespace-pre-line leading-relaxed" >
159174 { post . description }
160175 </ p >
161- < Button variant = "outline" size = "sm" asChild className = "w-full" >
162- < a href = { post . link } target = "_blank" rel = "noopener noreferrer" >
163- < ExternalLink className = "h-4 w-4 mr-2" />
164- Read on Medium
165- </ a >
166- </ Button >
167- </ CardContent >
168- </ Card >
176+ </ div >
177+ < footer className = "mt-4" >
178+ < a
179+ href = { post . link }
180+ target = "_blank"
181+ rel = "noopener noreferrer"
182+ className = "inline-flex items-center text-sm underline underline-offset-2 hover:text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
183+ >
184+ < ExternalLink className = "h-4 w-4 mr-2" />
185+ Read on Medium
186+ </ a >
187+ </ footer >
188+ </ article >
169189 ) ) }
170190 </ div >
171191
0 commit comments