페이지 레이아웃

이 페이지

편집자가 Default, Full Width, Landing Page 같은 페이지 템플릿 하나를 선택할 수 있게 합니다. select 필드가 선택 값을 저장하고, 페이지 라우트가 그 값을 Astro 레이아웃 컴포넌트에 매핑합니다. 편집자가 한 페이지 안에서 여러 섹션을 구성하고 순서를 바꿔야 한다면 blocks 필드를 사용하세요.

작동 방식

  1. 페이지 컬렉션에 template 선택 필드를 추가합니다
  2. 각 옵션에 해당하는 레이아웃 컴포넌트를 만듭니다
  3. 페이지 라우트에서 필드 값을 레이아웃에 매핑합니다

이는 EmDash의 선택 필드와 Astro의 컴포넌트 모델을 활용합니다.

필드 추가

관리자 UI에서 슬러그가 template인 선택 필드를 페이지 컬렉션에 추가하고 레이아웃 옵션(예: “Default”와 “Full Width”)을 설정합니다. 시드 데이터에서 같은 필드를 정의하려면 다음 객체를 컬렉션의 fields 배열에 추가하세요.

{
  "slug": "template",
  "label": "Template",
  "type": "select",
  "validation": {
    "options": ["Default", "Full Width"]
  },
  "defaultValue": "Default"
}

레이아웃 컴포넌트 만들기

각 레이아웃은 서로 다른 스타일로 콘텐츠를 기본 레이아웃으로 감쌉니다.

---
import type { ContentEntry, InferCollectionData } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "./Base.astro";

interface Props {
  page: ContentEntry<InferCollectionData<"pages">>;
}

const { page } = Astro.props;
---

<Base title={page.data.title}>
  <article class="page-default">
    <h1>{page.data.title}</h1>
    <PortableText value={page.data.content} />
  </article>
</Base>

<style>
  .page-default {
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 2rem 1rem;
  }
</style>
---
import type { ContentEntry, InferCollectionData } from "emdash";
import { PortableText } from "emdash/ui";
import Base from "./Base.astro";

interface Props {
  page: ContentEntry<InferCollectionData<"pages">>;
}

const { page } = Astro.props;
---

<Base title={page.data.title}>
  <article class="page-wide">
    <h1>{page.data.title}</h1>
    <PortableText value={page.data.content} />
  </article>
</Base>

<style>
  .page-wide {
    max-width: var(--wide-width);
    margin: 0 auto;
    padding: 2rem 1rem;
  }
</style>

라우트 연결

페이지 라우트에서 각 레이아웃을 가져오고 템플릿 값을 매핑합니다.

---
import { decodeSlug, getEmDashEntry } from "emdash";
import PageDefault from "../../layouts/PageDefault.astro";
import PageFullWidth from "../../layouts/PageFullWidth.astro";

const slug = decodeSlug(Astro.params.slug);

if (!slug) {
  return Astro.rewrite("/404");
}

const { entry: page } = await getEmDashEntry("pages", slug);

if (!page) {
  return Astro.rewrite("/404");
}

const layouts = new Map([
  ["Default", PageDefault],
  ["Full Width", PageFullWidth],
]);

const Layout = layouts.get(page.data.template ?? "") ?? PageDefault;
---

<Layout page={page} />

라우트는 작게 유지됩니다. 각 레이아웃 컴포넌트가 자신의 마크업과 스타일을 담당합니다. 레이아웃을 추가하려면 컴포넌트를 만들고, 선택 필드에 옵션을 추가하고, 맵에 한 줄을 추가하면 됩니다.

레이아웃 더 추가하기

흔히 쓰는 레이아웃 선택지:

  • Default — 좁은 콘텐츠 열로, 읽기에 적합
  • Full Width — 더 넓은 콘텐츠 영역으로, 사이드바 없음
  • Landing Page — 헤더/푸터 없이 히어로 섹션 사용
  • Sidebar — 옆에 위젯 영역이 있는 콘텐츠

각각은 src/layouts/ 디렉터리에 Astro 컴포넌트 하나가 늘어나고 라우트의 레이아웃 맵에 항목 하나가 늘어나는 것일 뿐입니다.