Les menus EmDash sont des listes ordonnées de liens gérées dans l’interface d’administration. Ils prennent en charge l’imbrication pour les menus déroulants et peuvent pointer vers des pages, articles, termes de taxonomie ou 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 ne porte ce nom.
Structure d’un menu
Un menu contient des métadonnées et un tableau d’éléments :
interface Menu {
id: string;
name: string; // Unique identifier ("primary", "footer")
label: string; // Display name ("Primary Navigation")
items: MenuItem[];
}
interface MenuItem {
id: string;
label: string;
url: string; // Resolved URL
target?: string; // "_blank" for new window
titleAttr?: string; // HTML title attribute
cssClasses?: string; // Custom CSS classes
children: MenuItem[]; // Nested items for dropdowns
}
Les URL sont résolues automatiquement selon le type d’élément :
- Éléments page/article →
/{collection}/{slug} - Éléments taxonomie →
/{taxonomy}/{slug} - Éléments collection →
/{collection}/ - Liens personnalisés → URL telle quelle
Rendre des menus imbriqués
Les éléments peuvent avoir des enfants pour les menus déroulants. 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’administration prend en charge cinq types :
| Type | Description | Résolution d’URL |
|---|---|---|
page | Lien vers une page | /{collection}/{slug} |
post | Lien vers un article | /{collection}/{slug} |
taxonomy | Lien vers catégorie ou étiquette | /{taxonomy}/{slug} |
collection | Lien vers archive de collection | /{collection}/ |
custom | URL externe ou personnalisée | Telle quelle |
Lister tous les menus
Utilisez getMenus() pour obtenir toutes les définitions de menus (sans éléments) :
import { getMenus } from "emdash";
const menus = await getMenus();
// Returns: [{ id, name, label }, ...]
Principalement utile pour des interfaces d’administration ou le débogage.
Créer des menus
Créez des menus dans l’admin à /_emdash/admin/menus ou via l’API d’administration :
POST /_emdash/api/menus
Content-Type: application/json
{
"name": "footer",
"label": "Footer Navigation"
}
Ajouter des éléments :
POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "page",
"referenceCollection": "pages",
"referenceId": "page_privacy",
"label": "Privacy Policy"
}
Ajouter 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éordonner et imbriquer
Mettez à jour l’ordre et la relation parent-enfant via le point de terminaison de réordonnancement :
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 }
]
}
Ainsi item_3 devient enfant de item_2, formant un menu déroulant.
Exemple complet
Exemple d’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— Identifiant unique du menu (chaîne)
Retour : Promise<Menu | null>
getMenus()
Liste toutes les définitions de menus sans éléments.
Retour : Promise<Array<{ id: string; name: string; label: string }>>