[Astro] 静的サイトジェネレーター [ページ、レイアウト]

ページ

Astro ページ

.astro 拡張子を使い Astro コンポーネントと同じ機能を持ちます。
src/pages/index.astro

---
---
<html lang="ja">
    <head>
        <title>Home</title>
    </head>
    <body>
        <h1>Welcom to my site.</h1>
    </body>
</html>

全てのページで同じ HTML 要素を繰り返すことを避けるために、共通の <head><body> 要素を独自のレイアウトコンポーネントに移動できます。
src/pages/index.astro

---
import MySiteLayout from '../layouts/MySiteLayout.astro';
---
<MySiteLayout>
    <p>レイアウトに包まれたコンテンツ</p>
</MySiteLayout>

レイアウト

レイアウトのサンプル

src/layouts/MySiteLayout.astro

---
import BaseHead from '../components/BaseHead.astro';
import Footer from '../components/Footer.astro';
const { title } = Astro.props;
---
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, intial-scale=1">
        <BaseHead title={ title } />
    </head>
    <body>
        <nav>
            <a href="#">Home</a>
            <a href="#">Blog</a>
            <a href="#">Inquiry</a>
        </nav>
        <h1>{ title }</h1>
        <article>
            <slot /> <!-- ここにコンテンツが挿入されます -->
        </article>
    </body>
</html>

src/pages/index.astro

---
import MySiteLayout from '../layouts/MySiteLayout.astro';
---
<MySiteLayout title="Home">
    <p>レイアウトに含まれたページのコンポーネント</p>
</MySiteLayout>

Markdown と MDX のレイアウト

Astro では layout というフロントマターの特別なプロパティを使用して、ページのレイアウトとして使用する .astro コンポーネントを指定できます。
src/pages/page.md

---
layout: ../layouts/BaseLayout.astro
title: "Hello, World!"
author: "uehara"
date: "2023/01/27"
---
すべてのフロントマターのプロパティは、Astro のレイアウトコンポーネントの rops として利用できます

`layout` プロパティは、Astro が提供する唯一の特別なプロパティです

`src/pages/` 内の Markdown と MDX ファイルの両方で使用できます

src/layouts/BaseLayout.astro

---
// 1. frontmatter prop によりフロントマターとその他のデータにアクセスできます
const { frontmatter } = Astro.props;
---
<html>
    <head>
        <!-- スタイルや meta タグなど、その他の head 要素をここに追加します -->
        <title>{ frontmatter.title }</title>
    </head>
    <body>
        <!-- 共通のヘッダーやフッターなど、他のUI コンポーネントをここに追加します -->
        <h1>{ frontmatter.title }, Author { frontmatter.author }</h1>
        <!-- 2. レンダリングされた HTML はデフォルトスロットに渡されます -->
        <slot />
        <p>post: { frontmatter.date }</p>
    </body>
</html>

MarkdownLayoutProps または MDXLayoutProps を使用して、レイアウトの Props 型を設定できます。 src/layouts/BaseLayout.astro

---
inport type { MarkdownLayoutProps } from 'astro';

type Props = MarkdownLayoutProps<{
    // フロントマターの props をここで定義します
    title: string;
    author: string;
    date: string;
}>:

const { frontmatter, url } = Astro.props;
---
<html>
    <head>
        <meta rel="canonical" href={ new URL(url, Astro.site).pathname }>
        <title>{ frontmatter.title }</title>
    </head>
    <body>
        <h1>{ frontmatter.title }, author { frontmatter.author }</h1>
        <slot />
        <p>post: { frontmatter.date }</p>
    </body>
</html>

Markdown レイアウトの Props

Markdown と MDX レイアウトは、Astro.props を介して次の情報にアクセスできます。

Astro.props = {
  file: "/home/user/projects/.../file.md",
  url: "/en/guides/markdown-content/",
  frontmatter: {
    /** ブログ記事のフロントマター */
    title: "Astro",
    date: "2023-01-27",
    author: "uehara",
    description: "Astro",
    /** 生成された値 */
    file: "/home/user/projects/.../file.md",
    url: "/en/guides/markdown-content/"
  },
  headings: [
    {
      "depth": 1,
      "text": "Astro",
      "slug": "astro"
    },
    {
      "depth": 2,
      "text": "Responsive partial hydration",
      "slug": "responsive-partial-hydration"
    }
    /* ... */
  ],
}

レイアウトを手動でインポートする (MDX)

src/pages/posts/first-post.mdx

---
layout: ../../layouts/BaseLayout.astro
title: 'MDX'
publishDate: '2023-01-27'
---
import BaseLayout from '../../layouts/BaseLayout.astro';

function fancyJsHelper() {
  return "YAML";
}

<BaseLayout title={ frontmatter.title } fancyJsHelper={ fancyJsHelper }>
  MDX
</BaseLayout>

src/layouts/BaseLayout.astro

---
const { title, fancyJsHelper } = Astro.props;
---
<!-- -->
<h1>{ title }</h1>
<slot /> <!-- コンテンツはここに挿入されます -->
<p>{ fancyJsHelper() }</p>
<!-- -->

.md, .mdx, .astro に対し同一のレイアウトを使用する

src/components/MyLayout.astro

---
const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{ title }</h1>
    <slot />
  </body>
</html>

レイアウトの入れ子

src/layouts/BlogPostLayout.astro

---
import BaseLayout from './BaseLayout.astro'
const {frontmatter} = Astro.props;
---
<BaseLayout url={ frontmatter.url }>
  <h1>{ frontmatter.title }</h1>
  <h2>post: { frontmatter.author }</h2>
  <slot />
</BaseLayout>