@@ -2,139 +2,202 @@ import Link from 'next/link';
22import Header from '../components/Header' ;
33import Footer from '../components/Footer' ;
44import { GetStaticProps } from 'next' ;
5- import { getPostsMetaOnly } from '../lib/posts' ;
5+ import { getPostsMetaOnly } from '../lib/posts' ;
66import AdSense from '../components/AdSense' ;
77import TopNotice from "../components/TopNotice" ;
8- import { catImages } from "../lib/mainImage" ;
8+ import { catImages } from "../lib/mainImage" ;
99
1010type Post = {
11- id : string ;
12- title : string ;
13- summary ?: string ;
14- description ?: string ;
11+ id : string ;
12+ title : string ;
13+ summary ?: string ;
14+ description ?: string ;
15+ date : string ;
16+ updated ?: string ;
1517} ;
1618
1719type HomeProps = {
18- allPostsData : Post [ ] ;
19- gradientsForPosts : string [ ] ;
20+ allPostsData : Post [ ] ;
21+ gradientsForPosts : string [ ] ;
2022} ;
2123
2224function shuffle < T > ( array : T [ ] ) : T [ ] {
23- const copy = [ ...array ] ;
24- for ( let i = copy . length - 1 ; i > 0 ; i -- ) {
25- const j = Math . floor ( Math . random ( ) * ( i + 1 ) ) ;
26- [ copy [ i ] , copy [ j ] ] = [ copy [ j ] , copy [ i ] ] ;
27- }
28- return copy ;
25+ const copy = [ ...array ] ;
26+ for ( let i = copy . length - 1 ; i > 0 ; i -- ) {
27+ const j = Math . floor ( Math . random ( ) * ( i + 1 ) ) ;
28+ [ copy [ i ] , copy [ j ] ] = [ copy [ j ] , copy [ i ] ] ;
29+ }
30+ return copy ;
2931}
3032
3133export const getStaticProps : GetStaticProps < HomeProps > = async ( ) => {
32- const allPostsData = getPostsMetaOnly ( ) ;
33- const [ latest , ...restAll ] = allPostsData ;
34-
35- const rest = restAll . filter ( ( post ) => post . id !== latest . id ) . slice ( 0 , 3 ) ;
36-
37- const shuffledImages = shuffle ( catImages ) . slice ( 0 , rest . length ) ;
38-
39- return {
40- props : {
41- allPostsData,
42- gradientsForPosts : shuffledImages ,
43- } ,
44- } ;
34+ const allPostsData = getPostsMetaOnly ( ) ;
35+
36+ const [ latest , ...restAll ] = allPostsData ;
37+ const rest = restAll . filter ( ( post ) => post . id !== latest . id ) . slice ( 0 , 3 ) ;
38+ const shuffledImages = shuffle ( catImages ) . slice ( 0 , rest . length ) ;
39+
40+ return {
41+ props : {
42+ allPostsData,
43+ gradientsForPosts : shuffledImages ,
44+ } ,
45+ } ;
4546} ;
4647
48+ // 날짜 내림차순 비교 (undefined 안전)
49+ const byDesc = ( a ?: string , b ?: string ) =>
50+ new Date ( b ?? '1970-01-01' ) . getTime ( ) - new Date ( a ?? '1970-01-01' ) . getTime ( ) ;
51+
4752export default function Home ( { allPostsData, gradientsForPosts } : HomeProps ) {
48- const [ latest , ...restAll ] = allPostsData ;
49- const rest = restAll . filter ( ( post ) => post . id !== latest . id ) . slice ( 0 , 3 ) ;
50-
51- return (
52- < >
53- < TopNotice />
54- < div className = "min-h-screen" >
55- < Header isDark = { false } />
56-
57- { /* Hero Section */ }
58- < section className = "text-center pt-40 pb-28 px-4" >
59- < h1 className = "text-4xl sm:text-5xl font-extrabold mb-6" > Hi, I’m a < strong > considerate developer</ strong > .</ h1 >
60- < p className = "text-lg text-gray-600 leading-loose space-y-2" >
61- I believe being considerate means writing < strong > clean, readable code</ strong > ,< br />
62- building < strong > predictable and testable systems</ strong > ,< br />
63- and delivering < strong > reliable, trustworthy services</ strong > that users can depend on.< br /> < br />
64- I’m constantly < strong > learning and growing</ strong > to become better at this,< br />
65- and this blog is where I share my < strong > journey as a learning developer</ strong > .
66- </ p >
67- </ section >
68-
69-
70- < div className = "bg-gray-50 pt-32 pb-20 px-4" >
71- < main className = "max-w-4xl mx-auto px-4 pb-32 space-y-24" >
72- { /* Latest Post */ }
73- < section >
53+ if ( ! allPostsData . length ) {
54+ return (
55+ < >
56+ < TopNotice />
57+ < Header isDark = { false } />
58+ < main className = "max-w-3xl mx-auto px-6 py-24" >
59+ < h1 className = "text-3xl font-bold" > No posts yet</ h1 >
60+ </ main >
61+ < Footer />
62+ </ >
63+ ) ;
64+ }
65+
66+ // 최신 글(작성일 기준)
67+ const [ latest , ...restAll ] = allPostsData ;
68+
69+ // 최근 업데이트 글(업데이트일 없으면 작성일로 대체)
70+ const updatedSorted = [ ...allPostsData ] . sort ( ( a , b ) =>
71+ byDesc ( a . updated ?? a . date , b . updated ?? b . date )
72+ ) ;
73+ const updatedPost =
74+ updatedSorted . find ( ( p ) => p . id !== latest . id ) ?? updatedSorted [ 0 ] ;
75+
76+ const rest = restAll
77+ . filter ( ( post ) => post . id !== updatedPost . id )
78+ . slice ( 0 , 3 ) ;
79+
80+ return (
81+ < >
82+ < TopNotice />
83+ < div className = "min-h-screen" >
84+ < Header isDark = { false } />
85+
86+ { /* Hero */ }
87+ < section className = "text-center pt-40 pb-28 px-4" >
88+ < h1 className = "text-4xl sm:text-5xl font-extrabold mb-6" >
89+ Hi, I’m a < strong > considerate developer</ strong > .
90+ </ h1 >
91+ < p className = "text-lg text-gray-600 leading-loose space-y-2" >
92+ I believe being considerate means writing < strong > clean, readable code</ strong > ,< br />
93+ building < strong > predictable and testable systems</ strong > ,< br />
94+ and delivering < strong > reliable, trustworthy services</ strong > that users can depend on.< br /> < br />
95+ I’m constantly < strong > learning and growing</ strong > to become better at this,< br />
96+ and this blog is where I share my < strong > journey as a learning developer</ strong > .
97+ </ p >
98+ </ section >
99+
100+ < div className = "bg-gray-50 pt-32 pb-20 px-4" >
101+ < main className = "max-w-4xl mx-auto px-4 pb-32 space-y-24" >
102+ { /* Latest Post */ }
103+ < section >
74104 < span className = "inline-block px-3 py-1 text-xs font-semibold rounded-full bg-white text-gray-500 uppercase tracking-wide" >
75105 Latest Post
76106 </ span >
77107
78- < h2 className = "mt-4 text-4xl font-extrabold text-gray-900" >
79- { latest . title }
80- </ h2 >
81-
82- < p className = "mt-4 text-lg text-gray-600 leading-relaxed" >
83- { latest . summary || 'No summary provided.' }
84- </ p >
85-
86- { latest . description && (
87- < p className = "mt-2 text-base text-gray-500 leading-relaxed" >
88- { latest . description }
89- </ p >
90- ) }
91-
92- < Link
93- href = { `/post/${ latest . id } ` }
94- className = "inline-block mt-6 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-6 py-2 rounded transition"
95- >
96- Continue Reading →
97- </ Link >
98- </ section >
99-
100- < AdSense />
101-
102- { /* More Posts */ }
103- < section >
104- < div className = "flex justify-between items-center mb-4" >
108+ < h2 className = "mt-4 text-4xl font-extrabold text-gray-900" >
109+ { latest . title }
110+ </ h2 >
111+
112+ < p className = "mt-4 text-lg text-gray-600 leading-relaxed" >
113+ { latest . summary || 'No summary provided.' }
114+ </ p >
115+
116+ { latest . description && (
117+ < p className = "mt-2 text-base text-gray-500 leading-relaxed" >
118+ { latest . description }
119+ </ p >
120+ ) }
121+
122+ < Link
123+ href = { `/post/${ latest . id } ` }
124+ className = "inline-block mt-6 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-6 py-2 rounded transition"
125+ >
126+ Continue Reading →
127+ </ Link >
128+ </ section >
129+
130+ { /* Recently Updated */ }
131+ < section >
132+ < span className = "inline-block px-3 py-1 text-xs font-semibold rounded-full bg-white text-gray-500 uppercase tracking-wide" >
133+ Recently Updated
134+ </ span >
135+
136+ < h2 className = "mt-4 text-3xl font-bold text-gray-900" >
137+ { updatedPost . title }
138+ </ h2 >
139+
140+ < p className = "mt-2 text-sm text-gray-500" >
141+ Updated: { updatedPost . updated ?? updatedPost . date }
142+ </ p >
143+
144+ < p className = "mt-4 text-lg text-gray-600 leading-relaxed" >
145+ { updatedPost . summary || 'No summary provided.' }
146+ </ p >
147+
148+ { updatedPost . description && (
149+ < p className = "mt-2 text-base text-gray-500 leading-relaxed" >
150+ { updatedPost . description }
151+ </ p >
152+ ) }
153+
154+ < Link
155+ href = { `/post/${ updatedPost . id } ` }
156+ className = "inline-block mt-6 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold px-6 py-2 rounded transition"
157+ >
158+ Read Updated Post →
159+ </ Link >
160+ </ section >
161+
162+ < AdSense />
163+
164+ { /* More Posts */ }
165+ < section >
166+ < div className = "flex justify-between items-center mb-4" >
105167 < span className = "inline-block px-3 py-1 text-xs font-semibold rounded-full bg-white text-gray-500 uppercase tracking-wide" >
106168 More Posts
107169 </ span >
108- < Link
109- href = "/post"
110- className = "text-sm text-gray-500 hover:text-gray-700 flex items-center gap-1"
111- >
112- Read all →
113- </ Link >
114- </ div >
115- < div className = "grid md:grid-cols-3 gap-6" >
116- { rest . map ( ( { id, title } , idx ) => (
117- < Link key = { id } href = { `/post/${ id } ` } >
118- < div
119- className = "flex flex-col justify-end p-6 h-48 sm:h-64 rounded-xl text-white shadow hover:shadow-xl transition"
120- style = { {
121- backgroundImage : `url(${ gradientsForPosts [ idx ] } )` ,
122- backgroundSize : "cover" ,
123- backgroundPosition : "center" ,
124- } }
125- >
126- < h3 className = "text-lg font-semibold leading-snug bg-black bg-opacity-50 p-2 rounded" >
127- { title }
128- </ h3 >
129- </ div >
130- </ Link >
131- ) ) }
132- </ div >
133- </ section >
134- </ main >
135- </ div >
136- </ div >
137- < Footer />
138- </ >
139- ) ;
170+ < Link
171+ href = "/post"
172+ className = "text-sm text-gray-500 hover:text-gray-700 flex items-center gap-1"
173+ >
174+ Read all →
175+ </ Link >
176+ </ div >
177+ < div className = "grid md:grid-cols-3 gap-6" >
178+ { rest . map ( ( { id, title } , idx ) => (
179+ < Link key = { id } href = { `/post/${ id } ` } >
180+ < div
181+ className = "flex flex-col justify-end p-6 h-48 sm:h-64 rounded-xl text-white shadow hover:shadow-xl transition"
182+ style = { {
183+ backgroundImage : `url(${ gradientsForPosts [ idx ] } )` ,
184+ backgroundSize : "cover" ,
185+ backgroundPosition : "center" ,
186+ } }
187+ >
188+ < h3 className = "text-lg font-semibold leading-snug bg-black/50 p-2 rounded" >
189+ { title }
190+ </ h3 >
191+ </ div >
192+ </ Link >
193+ ) ) }
194+ </ div >
195+ </ section >
196+ </ main >
197+ </ div >
198+ </ div >
199+
200+ < Footer />
201+ </ >
202+ ) ;
140203}
0 commit comments