EmDashのメニューは、管理画面から管理する順序付きリンクリストです。メニューはドロップダウン用のネストをサポートし、ページ、投稿、タクソノミー用語、または外部URLにリンクできます。
メニューのクエリ
getMenu() を使用して、一意の名前でメニューを取得します:
---
import { getMenu } from "emdash";
const primaryMenu = await getMenu("primary");
---
{primaryMenu && (
<nav>
<ul>
{primaryMenu.items.map(item => (
<li>
<a href={item.url}>{item.label}</a>
</li>
))}
</ul>
</nav>
)}
この名前のメニューが存在しない場合、関数は null を返します。
メニューの構造
メニューにはメタデータとアイテムの配列が含まれます:
interface Menu {
id: string;
name: string; // 一意の識別子("primary"、"footer")
label: string; // 表示名("Primary Navigation")
items: MenuItem[];
}
interface MenuItem {
id: string;
label: string;
url: string; // 解決されたURL
target?: string; // 新しいウィンドウの場合は "_blank"
titleAttr?: string; // HTMLのtitle属性
cssClasses?: string; // カスタムCSSクラス
children: MenuItem[]; // ドロップダウン用のネストされたアイテム
}
URLはアイテムタイプに基づいて自動的に解決されます:
- ページ/投稿アイテムは
/{collection}/{slug}に解決されます - タクソノミーアイテムは
/{taxonomy}/{slug}に解決されます - コレクションアイテムは
/{collection}/に解決されます - カスタムリンクはそのままURLを使用します
ネストされたメニューのレンダリング
メニューアイテムはドロップダウンナビゲーション用の子要素を持つことができます。children 配列を再帰的にレンダリングしてネストを処理します:
---
import { getMenu } from "emdash";
import type { MenuItem } from "emdash";
interface Props {
name: string;
}
const menu = await getMenu(Astro.props.name);
---
{menu && (
<nav class="nav">
<ul class="nav-list">
{menu.items.map(item => (
<li class:list={["nav-item", item.cssClasses]}>
<a
href={item.url}
target={item.target}
title={item.titleAttr}
aria-current={Astro.url.pathname === item.url ? "page" : undefined}
>
{item.label}
</a>
{item.children.length > 0 && (
<ul class="submenu">
{item.children.map(child => (
<li>
<a href={child.url} target={child.target}>
{child.label}
</a>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
)}
メニューアイテムタイプ
管理画面は5種類のメニューアイテムをサポートします:
| タイプ | 説明 | URL解決 |
|---|---|---|
page | ページへのリンク | /{collection}/{slug} |
post | 投稿へのリンク | /{collection}/{slug} |
taxonomy | カテゴリーまたはタグへのリンク | /{taxonomy}/{slug} |
collection | コレクションアーカイブへのリンク | /{collection}/ |
custom | 外部またはカスタムURL | そのまま |
すべてのメニューの一覧表示
getMenus() を使用して、すべてのメニュー定義(アイテムなし)を取得します:
import { getMenus } from "emdash";
const menus = await getMenus();
// 戻り値: [{ id, name, label, locale }, ...]
これは主に管理画面やデバッグに役立ちます。
メニューの作成
/_emdash/admin/menus の管理画面からメニューを作成するか、管理APIを使用します:
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "footer",
"label": "Footer Navigation"
}
メニューにアイテムを追加:
POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "page",
"referenceCollection": "pages",
"referenceId": "page_privacy",
"label": "Privacy Policy"
}
カスタム外部リンクを追加:
POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "custom",
"customUrl": "https://github.com/example",
"label": "GitHub",
"target": "_blank"
}
並び替えとネスト
reorderエンドポイントを使用して、アイテムの順序と親子関係を更新します:
POST /_emdash/api/menus/primary/reorder
Content-Type: application/json
{
"items": [
{ "id": "item_1", "parentId": null, "sortOrder": 0 },
{ "id": "item_2", "parentId": null, "sortOrder": 1 },
{ "id": "item_3", "parentId": "item_2", "sortOrder": 0 }
]
}
これにより、item_3 が item_2 の子となり、ドロップダウンが作成されます。
完全な例
以下の例は、プライマリナビゲーション付きのレスポンシブヘッダーを示します:
---
import { getMenu, getSiteSettings } from "emdash";
const settings = await getSiteSettings();
const primaryMenu = await getMenu("primary");
---
<html lang="en">
<head>
<title>{settings.title}</title>
</head>
<body>
<header class="header">
<a href="/" class="logo">
{settings.logo ? (
<img src={settings.logo.url} alt={settings.logo.alt || settings.title} />
) : (
settings.title
)}
</a>
{primaryMenu && (
<nav class="main-nav" aria-label="Main navigation">
<ul>
{primaryMenu.items.map(item => (
<li class:list={[item.cssClasses, { "has-children": item.children.length > 0 }]}>
<a
href={item.url}
target={item.target}
aria-current={Astro.url.pathname === item.url ? "page" : undefined}
>
{item.label}
</a>
{item.children.length > 0 && (
<ul class="dropdown">
{item.children.map(child => (
<li>
<a href={child.url} target={child.target}>{child.label}</a>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
)}
</header>
<main>
<slot />
</main>
</body>
</html>
APIリファレンス
getMenu(name)
すべてのアイテムと解決されたURLを含むメニューを名前で取得します。
パラメータ:
name— メニューの一意の識別子(string)
戻り値: Promise<Menu | null>
getMenus()
アイテムなしのすべてのメニュー定義を一覧表示します。
戻り値: Promise<Array<{ id: string; name: string; label: string; locale: string }>>