Les menus EmDash sont des listes ordonnées de liens que vous gérez via l’interface d’administration. Les menus prennent en charge l’imbrication pour les menus déroulants et peuvent pointer vers des pages, des articles, des termes de taxonomie ou des URL externes.
Interroger les menus
Utilisez getMenu() pour récupérer un menu par son nom unique :
---
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>
)}
La fonction renvoie null si aucun menu n’existe avec ce nom.
Structure du menu
Un menu contient des métadonnées et un tableau d’éléments :
interface Menu {
id: string;
name: string; // Identifiant unique ("primary", "footer")
label: string; // Nom d'affichage ("Primary Navigation")
items: MenuItem[];
}
interface MenuItem {
id: string;
label: string;
url: string; // URL résolue
target?: string; // "_blank" pour une nouvelle fenêtre
titleAttr?: string; // Attribut title HTML
cssClasses?: string; // Classes CSS personnalisées
children: MenuItem[]; // Éléments imbriqués pour les menus déroulants
}
Les URL sont résolues automatiquement en fonction du type d’élément :
- Éléments de page/article sont résolus en
/{collection}/{slug} - Éléments de taxonomie sont résolus en
/{taxonomy}/{slug} - Éléments de collection sont résolus en
/{collection}/ - Liens personnalisés utilisent l’URL telle quelle
Rendre les menus imbriqués
Les éléments de menu peuvent avoir des enfants pour la navigation déroulante. Gérez l’imbrication en rendant récursivement le tableau 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>
)}
Types d’éléments de menu
L’interface d’administration prend en charge cinq types d’éléments de menu :
| Type | Description | Résolution d’URL |
|---|---|---|
page | Lien vers une page | /{collection}/{slug} |
post | Lien vers un article | /{collection}/{slug} |
taxonomy | Lien vers une catégorie ou une balise | /{taxonomy}/{slug} |
collection | Lien vers une archive de collection | /{collection}/ |
custom | URL externe ou personnalisée | Telle quelle |
Lister tous les menus
Utilisez getMenus() pour récupérer toutes les définitions de menu (sans éléments) :
import { getMenus } from "emdash";
const menus = await getMenus();
// Renvoie : [{ id, name, label, locale }, ...]
Ceci est principalement utile pour les interfaces d’administration ou le débogage.
Créer des menus
Créez des menus via l’interface d’administration à /_emdash/admin/menus, ou utilisez l’API d’administration :
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "footer",
"label": "Footer Navigation"
}
Ajoutez des éléments à un menu :
POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "page",
"referenceCollection": "pages",
"referenceId": "page_privacy",
"label": "Privacy Policy"
}
Ajoutez un lien externe personnalisé :
POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "custom",
"customUrl": "https://github.com/example",
"label": "GitHub",
"target": "_blank"
}
Réorganisation et imbrication
Mettez à jour l’ordre des éléments et les relations parent-enfant avec le endpoint de réorganisation :
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 }
]
}
Cela fait de item_3 un enfant de item_2, créant un menu déroulant.
Exemple complet
L’exemple suivant montre un en-tête responsive avec navigation principale :
---
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>
Référence API
getMenu(name)
Récupère un menu par nom avec tous les éléments et URL résolues.
Paramètres :
name— L’identifiant unique du menu (string)
Renvoie : Promise<Menu | null>
getMenus()
Liste toutes les définitions de menu sans éléments.
Renvoie : Promise<Array<{ id: string; name: string; label: string; locale: string }>>