Menús de navegación
Los menús de EmDash son listas ordenadas de enlaces que gestionas a través de la interfaz de administración. Los menús admiten anidamiento para desplegables y pueden enlazar a páginas, entradas, términos de taxonomía o URLs externas.
Consultar menús
Sección titulada «Consultar menús»Usa getMenu() para obtener un menú por su nombre único:
---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 función devuelve null si no existe ningún menú con ese nombre.
Estructura del menú
Sección titulada «Estructura del menú»Un menú contiene metadatos y un array de elementos:
interface Menu { id: string; name: string; // Identificador unico ("primary", "footer") label: string; // Nombre visible ("Navegacion principal") items: MenuItem[];}
interface MenuItem { id: string; label: string; url: string; // URL resuelta target?: string; // "_blank" para nueva ventana titleAttr?: string; // Atributo HTML title cssClasses?: string; // Clases CSS personalizadas children: MenuItem[]; // Elementos anidados para menus desplegables}Las URLs se resuelven automáticamente según el tipo de elemento:
- Elementos de Página/Entrada se resuelven a
/{collection}/{slug} - Elementos de Taxonomía se resuelven a
/{taxonomy}/{slug} - Elementos de Colección se resuelven a
/{collection}/ - Enlaces personalizados usan la URL tal cual
Renderizar menús anidados
Sección titulada «Renderizar menús anidados»Los elementos del menú pueden tener hijos para navegación desplegable. Maneja el anidamiento renderizando recursivamente el array 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>)}Tipos de elementos del menú
Sección titulada «Tipos de elementos del menú»El administrador admite cinco tipos de elementos de menú:
| Tipo | Descripción | Resolución de URL |
|---|---|---|
page | Enlace a una página | /{collection}/{slug} |
post | Enlace a una entrada | /{collection}/{slug} |
taxonomy | Enlace a una categoría o etiqueta | /{taxonomy}/{slug} |
collection | Enlace a un archivo de colección | /{collection}/ |
custom | URL externa o personalizada | Se usa tal cual |
Listar todos los menús
Sección titulada «Listar todos los menús»Usa getMenus() para recuperar todas las definiciones de menús (sin elementos):
import { getMenus } from "emdash";
const menus = await getMenus();// Devuelve: [{ id, name, label }, ...]Esto es principalmente útil para interfaces de administración o depuración.
Crear menús
Sección titulada «Crear menús»Crea menús a través de la interfaz de administración en /_emdash/admin/menus, o usa la API de administración:
POST /_emdash/api/menusContent-Type: application/json
{ "name": "footer", "label": "Footer Navigation"}Añade elementos a un menú:
POST /_emdash/api/menus/footer/itemsContent-Type: application/json
{ "type": "page", "referenceCollection": "pages", "referenceId": "page_privacy", "label": "Privacy Policy"}Añade un enlace externo personalizado:
POST /_emdash/api/menus/footer/itemsContent-Type: application/json
{ "type": "custom", "customUrl": "https://github.com/example", "label": "GitHub", "target": "_blank"}Reordenar y Anidar
Sección titulada «Reordenar y Anidar»Actualiza el orden de los elementos y las relaciones padre-hijo con el endpoint de reordenación:
POST /_emdash/api/menus/primary/reorderContent-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 } ]}Esto convierte a item_3 en hijo de item_2, creando un desplegable.
Ejemplo completo
Sección titulada «Ejemplo completo»El siguiente ejemplo muestra una cabecera responsiva con navegación principal:
---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="Navegación principal"> <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>Referencia de la API
Sección titulada «Referencia de la API»getMenu(name)
Sección titulada «getMenu(name)»Obtiene un menú por nombre con todos sus elementos y URLs resueltas.
Parámetros:
name— El identificador único del menú (string)
Devuelve: Promise<Menu | null>
getMenus()
Sección titulada «getMenus()»Lista todas las definiciones de menús sin elementos.
Devuelve: Promise<Array<{ id: string; name: string; label: string }>>