Menus de navigation

Sur cette page

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 :

TypeDescriptionRésolution d’URL
pageLien vers une page/{collection}/{slug}
postLien vers un article/{collection}/{slug}
taxonomyLien vers une catégorie ou une balise/{taxonomy}/{slug}
collectionLien vers une archive de collection/{collection}/
customURL externe ou personnaliséeTelle 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 }>>