내비게이션 메뉴

이 페이지

메뉴를 사용하면 편집자가 사이트 템플릿을 변경하지 않고 정렬된 링크를 관리할 수 있습니다. 메뉴에는 primaryfooter와 같은 안정적인 이름이 있으며, 번역된 메뉴마다 별도의 항목 세트가 있습니다.

메뉴 만들기

EmDash 관리자의 Menus에서 메뉴를 만들고 정리합니다.

  1. Create Menu를 클릭하고 이름과 레이블을 입력합니다. 템플릿은 이름을 쿼리하고, 레이블은 관리자에서 메뉴를 식별합니다.

  2. Add Content를 클릭하여 항목을 링크하거나, Add Custom Link를 클릭하여 외부 URL 또는 루트 상대 사이트 경로를 입력합니다.

  3. Move upMove down을 사용하여 순서를 설정합니다. 항목을 편집하고 Parent를 선택하여 중첩합니다.

모든 로케일에서 동일한 메뉴 이름을 사용합니다. 다국어 사이트에서는 메뉴를 열고 Translations 패널을 사용하여 다른 로케일 버전을 만들고 편집합니다. EmDash는 동일한 콘텐츠 또는 택소노미 용어의 번역을 연결된 상태로 유지하므로, getMenu()는 요청된 로케일의 레이블과 슬러그를 사용할 수 있습니다.

메뉴 링크 해석 방법

콘텐츠 및 택소노미 메뉴 항목은 완성된 URL이 아닌 참조를 저장합니다. 템플릿이 getMenu()를 호출하면, EmDash는 현재 컬렉션과 로케일 데이터를 사용하여 해당 참조를 해석합니다.

메뉴 항목 종류템플릿에 반환되는 URL
콘텐츠 항목컬렉션의 urlPattern, 또는 컬렉션에 패턴이 없는 경우 /{collection}/{slug}
택소노미 용어해석된 용어 번역을 사용한 /{taxonomy}/{slug}
컬렉션 아카이브/{collection}/
사용자 정의 링크편집자가 입력한 외부 URL 또는 루트 상대 경로

반환되는 각 항목에는 레이블, 선택적 대상, title 속성, CSS 클래스, 중첩된 children도 포함됩니다. 아래 렌더링 예제에서 이 값들을 직접 사용합니다.

메뉴 렌더링

서버 렌더링되는 Astro 컴포넌트에서 getMenu()를 호출합니다. 이름이 존재하지 않으면 null을 반환합니다.

다음 레이아웃은 기본 메뉴와 한 단계의 중첩 항목을 렌더링합니다:

---
import { getMenu } from "emdash";
import { getRelativeLocaleUrl } from "astro:i18n";

const locale = Astro.currentLocale;
const menu = await getMenu("primary", { locale });

function menuHref(url: string) {
  return locale && url.startsWith("/")
    ? getRelativeLocaleUrl(locale, url)
    : url;
}
---

{menu && menu.items.length > 0 && (
  <nav aria-label="기본 내비게이션">
    <ul>
      {menu.items.map((item) => {
        const href = menuHref(item.url);

        return (
          <li class:list={item.cssClasses}>
            <a
              href={href}
              target={item.target}
              rel={item.target === "_blank" ? "noopener noreferrer" : undefined}
              title={item.titleAttr}
              aria-current={Astro.url.pathname === href ? "page" : undefined}
            >
              {item.label}
            </a>

            {item.children.length > 0 && (
              <ul>
                {item.children.map((child) => {
                  const childHref = menuHref(child.url);

                  return (
                    <li class:list={child.cssClasses}>
                      <a
                        href={childHref}
                        target={child.target}
                        rel={child.target === "_blank" ? "noopener noreferrer" : undefined}
                        title={child.titleAttr}
                        aria-current={Astro.url.pathname === childHref ? "page" : undefined}
                      >
                        {child.label}
                      </a>
                    </li>
                  );
                })}
              </ul>
            )}
          </li>
        );
      })}
    </ul>
  </nav>
)}

getMenu()는 먼저 명시적 locale을 선택하고, 그 다음 현재 요청 로케일, 그 다음 구성된 기본 로케일을 선택합니다. 해당 로케일에 메뉴나 참조된 항목이 없으면, 검색은 구성된 폴백 체인을 따릅니다.

메뉴 항목 URL에는 컬렉션 URL 패턴이나 택소노미 경로가 포함되지만, Astro의 로케일 접두사는 포함되지 않습니다. menuHref() 헬퍼는 루트 상대 링크에 해당 접두사를 추가하고 외부 링크는 변경하지 않습니다.

이 예제는 한 단계의 자식 레벨을 렌더링하며, 전형적인 드롭다운을 다룹니다. 편집자가 더 깊은 내비게이션을 만들 수 있다면, 항목 마크업을 동일한 규칙으로 각 항목의 children을 렌더링하는 재귀 컴포넌트로 이동합니다.

위젯 영역에서 메뉴 사용

메뉴 위젯은 기존 메뉴를 위젯 영역 안에 배치합니다. 위젯은 현재 요청 로케일의 메뉴를 읽습니다. 사이트에 사용자 정의 중첩 마크업이나 명시적 로케일 URL 처리가 필요한 경우 위의 직접 렌더링 패턴을 사용합니다.

메뉴 데이터 직접 쿼리

템플릿이 한 메뉴의 항목이 아닌 사용 가능한 메뉴 정의가 필요한 경우 getMenus()를 사용합니다. 런타임 API 참조에서 쿼리 시그니처와 반환 값을 확인할 수 있습니다.

프로그래밍 방식의 메뉴 변경의 경우, Bearer 토큰으로 인증하고 상태를 변경하는 모든 요청에 X-EmDash-Request: 1을 추가합니다. 요청 본문과 응답은 메뉴 엔드포인트를 참조하세요.

로케일 라우팅과 폴백 구성은 국제화를 참조하세요.