콘텐츠로 이동

네비게이션 메뉴

EmDash 메뉴는 관리자 인터페이스를 통해 관리하는 링크의 정렬된 목록입니다. 메뉴는 드롭다운을 위한 중첩을 지원하며, 페이지, 게시물, 분류 용어 또는 외부 URL로 연결할 수 있습니다.

getMenu()를 사용하여 고유한 이름으로 메뉴를 가져옵니다:

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

해당 이름의 메뉴가 존재하지 않으면 함수는 null을 반환합니다.

메뉴는 메타데이터와 항목 배열을 포함합니다:

interface Menu {
id: string;
name: string; // 고유 식별자 ("primary", "footer")
label: string; // 표시 이름 ("기본 내비게이션")
items: MenuItem[];
}
interface MenuItem {
id: string;
label: string;
url: string; // 해석된 URL
target?: string; // 새 창이면 "_blank"
titleAttr?: string; // HTML title attribute
cssClasses?: string; // 사용자 지정 CSS 클래스
children: MenuItem[]; // 드롭다운용 중첩 항목
}

URL은 항목 유형에 따라 자동으로 해결됩니다:

  • 페이지/게시물 항목은 /{collection}/{slug}로 해결됩니다.
  • 분류 항목은 /{taxonomy}/{slug}로 해결됩니다.
  • 컬렉션 항목은 /{collection}/로 해결됩니다.
  • 사용자 정의 링크는 URL을 있는 그대로 사용합니다.

메뉴 항목은 드롭다운 탐색을 위해 자식 항목을 가질 수 있습니다. children 배열을 재귀적으로 렌더링하여 중첩을 처리합니다:

astro title="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>
)}

관리자는 다섯 가지 유형의 메뉴 항목을 지원합니다:

유형설명URL 해결 방식
page페이지로의 링크/{collection}/{slug}
post게시물로의 링크/{collection}/{slug}
taxonomy카테고리 또는 태그로의 링크/{taxonomy}/{slug}
collection컬렉션 아카이브로의 링크/{collection}/
custom외부 또는 사용자 정의 URL있는 그대로 사용

getMenus()를 사용하여 모든 메뉴 정의(항목 없이)를 검색합니다:

import { getMenus } from "emdash";
const menus = await getMenus();
// 반환값: [{ id, name, label }, ...]

이는 주로 관리자 인터페이스나 디버깅에 유용합니다.

/_emdash/admin/menus의 관리자 인터페이스를 통해 메뉴를 생성하거나, 관리자 API를 사용합니다:

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

메뉴에 항목 추가하기:

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

사용자 정의 외부 링크 추가하기:

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

재정렬 엔드포인트를 사용하여 항목 순서와 부모-자식 관계를 업데이트합니다:

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

이렇게 하면 item_3이 item_2의 자식이 되어 드롭다운을 생성합니다.

다음 예제는 기본 탐색이 포함된 반응형 헤더를 보여줍니다:

astro title="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="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>

이름으로 메뉴를 가져와 모든 항목과 해결된 URL을 포함합니다.

매개변수:

  • name — 메뉴의 고유 식별자 (문자열)

반환값: Promise<Menu | null>

항목 없이 모든 메뉴 정의를 나열합니다.

반환값: Promise<Array<{ id: string; name: string; label: string }>>