편집자가 Default, Full Width, Landing Page 같은 페이지 템플릿 하나를 선택할 수 있게 합니다. select 필드가 선택 값을 저장하고, 페이지 라우트가 그 값을 Astro 레이아웃 컴포넌트에 매핑합니다. 편집자가 한 페이지 안에서 여러 섹션을 구성하고 순서를 바꿔야 한다면 blocks 필드를 사용하세요.
작동 방식
- 페이지 컬렉션에
template선택 필드를 추가합니다 - 각 옵션에 해당하는 레이아웃 컴포넌트를 만듭니다
- 페이지 라우트에서 필드 값을 레이아웃에 매핑합니다
이는 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 컴포넌트 하나가 늘어나고 라우트의 레이아웃 맵에 항목 하나가 늘어나는 것일 뿐입니다.