Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/post-card.tsx
Original file line number Diff line number Diff line change
@@ -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
}>
Expand Down
4 changes: 2 additions & 2 deletions src/components/post-meta.tsx
Original file line number Diff line number Diff line change
@@ -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, "category" | "date" | "pinned" | "readingMinutes">
post: Pick<PostSummary, "category" | "date" | "pinned" | "readingMinutes">
}>

// 날짜는 시각이 아니라 달력상의 하루라, 표준시를 UTC 로 고정해 하루가 밀리지 않게 한다.
Expand Down
44 changes: 28 additions & 16 deletions src/lib/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<PostFrontmatter, "description" | "tags"> & {
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 })
Expand Down