44 InferGetStaticPropsType
55} from 'next' ;
66import { MDXRemote , MDXRemoteSerializeResult } from 'next-mdx-remote' ;
7- import { getAllPostIds , getPostData } from '../../lib/posts' ;
7+ import { getAllPostIds , getPostData , getPostsMetaOnly , PostMeta } from '../../lib/posts' ;
88import Header from '../../components/Header' ;
99import Panel from '../../components/Panel' ;
1010import { BlueText , RedText , GreenText } from '../../components/Highlight' ;
@@ -15,11 +15,13 @@ import Link from 'next/link';
1515import { List } from 'lucide-react' ;
1616import { ArrowDownCircle } from 'lucide-react' ;
1717import { Tabs , Tab } from "../../components/Tabs" ;
18+ import { serialize } from "next-mdx-remote/serialize" ;
1819
1920type PostData = {
2021 id : string ;
2122 title : string ;
2223 date : string ;
24+ tags ?: string [ ] ;
2325 mdxSource : MDXRemoteSerializeResult ;
2426} ;
2527
@@ -28,12 +30,32 @@ export const getStaticPaths: GetStaticPaths = async () => {
2830 return { paths, fallback : false } ;
2931} ;
3032
31- export const getStaticProps : GetStaticProps < { postData : PostData } > = async ( { params } ) => {
33+ export const getStaticProps : ( { params} : { params : any } ) => Promise < {
34+ props : {
35+ relatedPosts : PostMeta [ ] ;
36+ postData : PostData & { id : string ; mdxSource : Awaited < ReturnType < typeof serialize > > }
37+ }
38+ } > = async ( { params } ) => {
3239 const postData = await getPostData ( params ?. id as string ) ;
33- return { props : { postData } } ;
40+ const allPosts = getPostsMetaOnly ( ) ;
41+
42+ const relatedPosts = allPosts
43+ . filter (
44+ ( post ) =>
45+ post . id !== postData . id &&
46+ post . tags ?. some ( ( tag ) => postData . tags ?. includes ( tag ) )
47+ )
48+ . slice ( 0 , 5 ) ;
49+
50+ return {
51+ props : {
52+ postData,
53+ relatedPosts,
54+ } ,
55+ } ;
3456} ;
3557
36- export default function Post ( { postData } : InferGetStaticPropsType < typeof getStaticProps > ) {
58+ export default function Post ( { postData, relatedPosts } : InferGetStaticPropsType < typeof getStaticProps > ) {
3759 const [ toc , activeId ] = useTocObserver ( ) ;
3860
3961 const scrollRef = useRef < HTMLDivElement > ( null ) ;
@@ -82,6 +104,28 @@ export default function Post({ postData }: InferGetStaticPropsType<typeof getSta
82104 < article >
83105 < MDXRemote { ...postData . mdxSource } components = { components } />
84106 </ article >
107+ { relatedPosts . length > 0 && (
108+ < div className = "mt-20 p-6 border rounded-2xl bg-gray-50 dark:bg-gray-800 shadow-sm" >
109+ < h2 className = "text-xl font-bold flex items-center gap-2 mb-6" >
110+ 🏷️ < span > 같은 태그의 글 보기</ span >
111+ </ h2 >
112+ < ul className = "space-y-4" >
113+ { relatedPosts . map ( ( post ) => (
114+ < li key = { post . id } className = "flex flex-col" >
115+ < Link
116+ href = { `/post/${ post . id } ` }
117+ className = "text-lg font-medium text-blue-600 hover:underline dark:text-blue-400"
118+ >
119+ { post . title }
120+ </ Link >
121+ < span className = "text-sm text-gray-500 dark:text-gray-400" >
122+ { post . tags ?. map ( ( tag ) => `#${ tag } ` ) . join ( ' ' ) }
123+ </ span >
124+ </ li >
125+ ) ) }
126+ </ ul >
127+ </ div >
128+ ) }
85129 </ main >
86130
87131 { /* Table of contents */ }
0 commit comments