diff --git a/src/components/post-card.tsx b/src/components/post-card.tsx index 05d2480..b8bca03 100644 --- a/src/components/post-card.tsx +++ b/src/components/post-card.tsx @@ -1,10 +1,10 @@ import Link from "next/link" -import type { Post } from "@/lib/posts" +import type { PostSummary } from "@/lib/posts" import { PostMeta } from "./post-meta" import { PostTags } from "./post-tags" type PostCardProps = Readonly<{ - post: Post + post: PostSummary /** 카드가 놓인 자리의 바로 위 제목 다음 단계여야 문서 개요에 구멍이 생기지 않는다. */ headingLevel?: 2 | 3 }> diff --git a/src/components/post-meta.tsx b/src/components/post-meta.tsx index f07a181..6318942 100644 --- a/src/components/post-meta.tsx +++ b/src/components/post-meta.tsx @@ -1,8 +1,8 @@ import { siteConfig } from "@/config/site" -import type { Post } from "@/lib/posts" +import type { PostSummary } from "@/lib/posts" type PostMetaProps = Readonly<{ - post: Pick + post: Pick }> // 날짜는 시각이 아니라 달력상의 하루라, 표준시를 UTC 로 고정해 하루가 밀리지 않게 한다. diff --git a/src/lib/posts.ts b/src/lib/posts.ts index 5acc5bf..2d7aaa3 100644 --- a/src/lib/posts.ts +++ b/src/lib/posts.ts @@ -3,7 +3,12 @@ import { basename, join } from "node:path" import { VFile } from "vfile" import { matter } from "vfile-matter" import { siteConfig } from "@/config/site" -import { extractPostExcerpt, PostContentError, parsePostFrontmatter } from "@/lib/markdown" +import { + extractPostExcerpt, + PostContentError, + type PostFrontmatter, + parsePostFrontmatter, +} from "@/lib/markdown" import type { AdjacentPosts, PaginatedPosts, TaxonomyItem } from "@/lib/post-collections" import { findAdjacentPosts, @@ -42,21 +47,28 @@ export class EmptyPostCollectionError extends Error { } } -export type Post = { - readonly slug: string - readonly title: string - readonly description: string - readonly date: string - readonly tags: readonly string[] - readonly category: string - readonly draft: boolean - readonly ogImage?: string - readonly pinned: boolean - readonly toc: boolean - readonly readingMinutes: number - readonly excerpt: string - readonly content: string -} +/** + * 게시글 메타데이터 요약 모델 (Single Source of Truth: PostFrontmatter 파생) + * 목록, 태그, 카테고리, 사이트맵 렌더링에 필요한 속성들을 본문(content) 없이 포함합니다. + */ +export type PostSummary = Readonly< + Omit & { + readonly slug: string + readonly description: string + readonly tags: readonly string[] + readonly readingMinutes: number + readonly excerpt: string + } +> + +/** + * 게시글 전체 상세 모델 + * PostSummary 모델을 확장하여 마크다운 본문(content)을 포함합니다. + */ +export type Post = PostSummary & + Readonly<{ + readonly content: string + }> export function readPostsFromDirectory(directory: string = POSTS_DIRECTORY): readonly Post[] { mkdirSync(directory, { recursive: true })