ページレイアウト
このページで分かること
selectフィールドにレイアウトの選択を保存し、ページのルートでAstroのレイアウトコンポーネントに対応づける仕組みpagesコレクションへのtemplateフィールドの追加方法(管理画面、またはシードデータ)- レイアウトコンポーネントの作り方と、レイアウトを増やすときの手順
このページの目次
編集者がページごとにレイアウトを選べるようにします。たとえば、Default、Full Width、Landing Pageのようなレイアウトです。選択は select フィールドに保存し、ページのルートがその値をAstroのレイアウトコンポーネントに対応づけます。
仕組み
- pagesコレクションに、
templateという選択(select)フィールドを追加します - 選択肢ごとにレイアウトコンポーネントを作成します
- ページのルートで、フィールドの値をレイアウトに対応づけます
この方法は、EmDashの選択フィールドとAstroのコンポーネントモデルを使います。
やさしい解説
WordPressの「ページテンプレート」(固定ページの編集画面でテンプレートを選ぶ機能)と同じことを、EmDashでは選択フィールドとAstroのコンポーネントで実現します。編集者は編集画面の選択肢から「Full Width」などを選び、その値がエントリーに保存されます。ページのルート(URLに対応するAstroのファイル)は、保存された値を見て、使うレイアウトコンポーネントを切り替えます。
フィールドの追加
管理画面で、pagesコレクションに、スラッグが 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>
ルートへの接続
ページのルートで、各レイアウトをインポートし、templateの値を対応づけます。
---
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.redirect("/404");
}
const { entry: page } = await getEmDashEntry("pages", slug);
if (!page) {
return Astro.redirect("/404");
}
const layouts = new Map([
["Default", PageDefault],
["Full Width", PageFullWidth],
]);
const Layout = layouts.get(page.data.template ?? "") ?? PageDefault;
---
<Layout page={page} />
ルートは小さいままです。マークアップとスタイルは、それぞれのレイアウトコンポーネントが持ちます。レイアウトを追加する手順は、コンポーネントを作成し、選択フィールドに選択肢を追加し、対応表(Map)に1行追加するだけです。
やさしい解説
ルートのコードにある new Map([...]) が、「フィールドの値」と「使うレイアウト」の対応表です。値が空の場合や、対応表にない値の場合は、?? PageDefault によって既定のレイアウトが使われます。選択肢の文字列(例:"Full Width")は、シードファイル、管理画面の選択肢、この対応表のすべてで完全に一致させる必要があります。
レイアウトの追加
よく使われるレイアウトの選択肢は次のとおりです。
- Default:幅の狭いコンテンツの列。読みやすさに向いています
- Full Width:幅の広いコンテンツの領域。サイドバーはありません
- Landing Page:ヘッダーとフッターがなく、ヒーローセクションがあります
- Sidebar:コンテンツの横にウィジェットエリアがあります
どれも、src/layouts/ ディレクトリに置くAstroコンポーネントを1つ増やし、ルートのレイアウトの対応表に1項目を追加するだけです。