블로그 만들기

이 페이지

이 가이드는 콘텐츠 유형 정의부터 카테고리 및 태그가 포함된 게시물 표시까지 EmDash로 블로그를 만드는 방법을 다룹니다.

사전 요구 사항

  • 설정되고 실행 중인 EmDash 사이트(시작하기 참조)
  • Astro 컴포넌트에 대한 기본 지식

Posts 컬렉션 정의하기

EmDash는 설정 중에 기본 “posts” 컬렉션을 생성합니다. 관리 대시보드 또는 API에서 사용자 정의하세요.

기본 posts 컬렉션에는 다음이 포함됩니다:

  • title - 게시물 제목
  • slug - URL 친화적 식별자
  • content - 리치 텍스트 본문
  • excerpt - 짧은 설명
  • featured_image - 헤더 이미지(선택 사항)
  • status - 초안, 게시됨 또는 예약됨
  • publishedAt - 게시 날짜(시스템 필드)

첫 번째 게시물 만들기

  1. /_emdash/admin에서 관리 대시보드를 엽니다

  2. 사이드바에서 Posts를 클릭합니다

    제목, 상태 및 날짜를 표시하는 EmDash 게시물 목록
  3. New Post를 클릭합니다

    제목, 콘텐츠 및 게시 옵션이 있는 EmDash 게시물 편집기
  4. 제목을 입력하고 리치 텍스트 편집기를 사용하여 콘텐츠를 작성합니다

  5. 사이드바 패널에서 카테고리 및 태그를 추가합니다

  6. 상태를 Published로 설정합니다

  7. Save를 클릭합니다

게시물이 이제 게시되어 즉시 나타납니다.

사이트에 게시물 표시하기

모든 게시물 나열하기

다음 페이지는 게시된 모든 게시물을 표시합니다:

---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";

const { entries: posts } = await getEmDashCollection("posts", {
  status: "published",
});

// Sort by publication date, newest first
const sortedPosts = posts.sort(
  (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0)
);
---

<Base title="Blog">
  <h1>Blog</h1>
  <ul>
    {sortedPosts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>
          <h2>{post.data.title}</h2>
          <p>{post.data.excerpt}</p>
          <time datetime={post.data.publishedAt?.toISOString()}>
            {post.data.publishedAt?.toLocaleDateString()}
          </time>
        </a>
      </li>
    ))}
  </ul>
</Base>

개별 게시물 표시하기

다음 동적 라우트는 개별 게시물을 렌더링합니다:

---
import { getEmDashCollection, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "../../layouts/Base.astro";

export async function getStaticPaths() {
  const { entries: posts } = await getEmDashCollection("posts", {
    status: "published",
  });

  return posts.map((post) => ({
    params: { slug: post.data.slug },
  }));
}

const { slug } = Astro.params;
const { entry: post } = await getEmDashEntry("posts", slug);

if (!post) {
  return Astro.redirect("/404");
}
---

<Base title={post.data.title}>
  <article>
    {post.data.featured_image && (
      <img src={post.data.featured_image} alt="" />
    )}
    <h1>{post.data.title}</h1>
    <time datetime={post.data.publishedAt?.toISOString()}>
      {post.data.publishedAt?.toLocaleDateString()}
    </time>
    <PortableText value={post.data.content} />
  </article>
</Base>

카테고리 및 태그 추가하기

EmDash에는 카테고리 및 태그 분류 체계가 내장되어 있습니다. 용어 생성 및 관리에 대한 자세한 내용은 분류 체계를 참조하세요.

카테고리별로 게시물 필터링하기

다음 라우트는 단일 카테고리의 게시물을 나열합니다:

---
import { getEmDashCollection, getTerm, getTaxonomyTerms } from "emdash";
import Base from "../../layouts/Base.astro";

export async function getStaticPaths() {
  const categories = await getTaxonomyTerms("category");

  // Flatten hierarchical categories
  const flatten = (terms) => terms.flatMap((t) => [t, ...flatten(t.children)]);

  return flatten(categories).map((cat) => ({
    params: { slug: cat.slug },
    props: { category: cat },
  }));
}

const { category } = Astro.props;

const { entries: posts } = await getEmDashCollection("posts", {
  status: "published",
  where: { category: category.slug },
});
---

<Base title={category.label}>
  <h1>{category.label}</h1>
  {category.description && <p>{category.description}</p>}

  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>
</Base>

게시물 카테고리 표시하기

다음 컴포넌트는 게시물에 할당된 카테고리 및 태그를 표시합니다:

---
import { getEntryTerms } from "emdash";

interface Props {
  postId: string;
}

const { postId } = Astro.props;
const categories = await getEntryTerms("posts", postId, "category");
const tags = await getEntryTerms("posts", postId, "tag");
---

<div class="post-meta">
  {categories.length > 0 && (
    <div class="categories">
      <span>Categories:</span>
      {categories.map((cat) => (
        <a href={`/category/${cat.slug}`}>{cat.label}</a>
      ))}
    </div>
  )}

  {tags.length > 0 && (
    <div class="tags">
      <span>Tags:</span>
      {tags.map((tag) => (
        <a href={`/tag/${tag.slug}`}>{tag.label}</a>
      ))}
    </div>
  )}
</div>

페이지네이션 추가하기

많은 게시물이 있는 블로그의 경우 다음 라우트는 게시물 목록을 페이지로 나눕니다:

---
import { getEmDashCollection } from "emdash";
import Base from "../../../layouts/Base.astro";

const POSTS_PER_PAGE = 10;

export async function getStaticPaths() {
  const { entries: allPosts } = await getEmDashCollection("posts", {
    status: "published",
  });

  const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE);

  return Array.from({ length: totalPages }, (_, i) => ({
    params: { page: String(i + 1) },
    props: { currentPage: i + 1, totalPages },
  }));
}

const { currentPage, totalPages } = Astro.props;

const { entries: allPosts } = await getEmDashCollection("posts", {
  status: "published",
});

const sortedPosts = allPosts.sort(
  (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0)
);

const start = (currentPage - 1) * POSTS_PER_PAGE;
const posts = sortedPosts.slice(start, start + POSTS_PER_PAGE);
---

<Base title={`Blog - Page ${currentPage}`}>
  <h1>Blog</h1>

  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>

  <nav>
    {currentPage > 1 && (
      <a href={`/blog/page/${currentPage - 1}`}>Previous</a>
    )}
    <span>Page {currentPage} of {totalPages}</span>
    {currentPage < totalPages && (
      <a href={`/blog/page/${currentPage + 1}`}>Next</a>
    )}
  </nav>
</Base>

RSS 피드 추가하기

다음 엔드포인트는 블로그의 RSS 피드를 생성합니다:

import rss from "@astrojs/rss";
import { getEmDashCollection } from "emdash";

export async function GET(context) {
	const { entries: posts } = await getEmDashCollection("posts", {
		status: "published",
	});

	return rss({
		title: "My Blog",
		description: "A blog built with EmDash",
		site: context.site,
		items: posts.map((post) => ({
			title: post.data.title,
			pubDate: post.data.publishedAt,
			description: post.data.excerpt,
			link: `/blog/${post.data.slug}`,
		})),
	});
}

피드는 @astrojs/rss 패키지에 의존합니다. 다음 명령으로 설치합니다:

npm install @astrojs/rss

다음 단계