Zum Inhalt springen

Navigationsmenüs

EmDash-Menüs sind geordnete Listen von Links, die Sie über die Admin-Oberfläche verwalten. Menüs unterstützen Verschachtelung für Dropdowns und können auf Seiten, Beiträge, Taxonomie-Begriffe oder externe URLs verlinken.

Verwenden Sie getMenu(), um ein Menü anhand seines eindeutigen Namens abzurufen:

src/layouts/Base.astro
---
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>
)}

Die Funktion gibt null zurück, wenn kein Menü mit diesem Namen existiert.

Ein Menü enthält Metadaten und ein Array von Elementen:

interface Menu {
id: string;
name: string; // Eindeutige Kennung ("primary", "footer")
label: string; // Anzeigename ("Hauptnavigation")
items: MenuItem[];
}
interface MenuItem {
id: string;
label: string;
url: string; // Aufgeloeste URL
target?: string; // "_blank" fuer neues Fenster
titleAttr?: string; // HTML-title-Attribut
cssClasses?: string; // Benutzerdefinierte CSS-Klassen
children: MenuItem[]; // Verschachtelte Eintraege fuer Dropdowns
}

URLs werden automatisch basierend auf dem Elementtyp aufgelöst:

  • Seiten-/Beitragselemente werden zu /{collection}/{slug} aufgelöst
  • Taxonomie-Elemente werden zu /{taxonomy}/{slug} aufgelöst
  • Sammlungselemente werden zu /{collection}/ aufgelöst
  • Benutzerdefinierte Links verwenden die URL unverändert

Menüelemente können Kinder für die Dropdown-Navigation haben. Behandeln Sie die Verschachtelung durch rekursives Rendern des children-Arrays:

src/components/Navigation.astro
---
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>
)}

Die Admin-Oberfläche unterstützt fünf Arten von Menüelementen:

TypBeschreibungURL-Auflösung
pageLink zu einer Seite/{collection}/{slug}
postLink zu einem Beitrag/{collection}/{slug}
taxonomyLink zu einer Kategorie oder einem Tag/{taxonomy}/{slug}
collectionLink zu einem Sammlungsarchiv/{collection}/
customExterne oder benutzerdefinierte URLWird unverändert verwendet

Verwenden Sie getMenus(), um alle Menüdefinitionen (ohne Elemente) abzurufen:

import { getMenus } from "emdash";
const menus = await getMenus();
// Gibt zurück: [{ id, name, label }, ...]

Dies ist hauptsächlich für Admin-Oberflächen oder Debugging nützlich.

Erstellen Sie Menüs über die Admin-Oberfläche unter /_emdash/admin/menus oder verwenden Sie die Admin-API:

POST /_emdash/api/menus
Content-Type: application/json
{
"name": "footer",
"label": "Footer Navigation"
}

Elemente zu einem Menü hinzufügen:

POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "page",
"referenceCollection": "pages",
"referenceId": "page_privacy",
"label": "Privacy Policy"
}

Einen benutzerdefinierten externen Link hinzufügen:

POST /_emdash/api/menus/footer/items
Content-Type: application/json
{
"type": "custom",
"customUrl": "https://github.com/example",
"label": "GitHub",
"target": "_blank"
}

Aktualisieren Sie die Reihenfolge der Elemente und Eltern-Kind-Beziehungen mit dem Reorder-Endpoint:

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 }
]
}

Dadurch wird item_3 zu einem Kind von item_2 und erstellt ein Dropdown.

Das folgende Beispiel zeigt einen responsiven Header mit primärer Navigation:

src/layouts/Base.astro
---
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="Hauptnavigation">
<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>

Ruft ein Menü anhand des Namens mit allen Elementen und aufgelösten URLs ab.

Parameter:

  • name — Der eindeutige Bezeichner des Menüs (String)

Gibt zurück: Promise<Menu | null>

Listet alle Menüdefinitionen ohne Elemente auf.

Gibt zurück: Promise<Array<{ id: string; name: string; label: string }>>