Im vorherigen Post haben wir die Komponenten für das Flyout-Menü erstellt und die grundlegende Integration durchgeführt, aber die angezeigten Daten kamen aus einer statischen Variable. Jetzt werden wir das Menü mit unserem Headless CMS Contentful verbinden.
Hier ist das GitHub Repo mit dem gesamten Code und darunter der Link zur Beispielwebsite.
Example page hosted on Vercel -> https://nextjs14-contentful-syntax-highlighting.vercel.app/
Verwendeter Stack
Ich werde mit meinem Standard-Stack beginnen:
Next.js 14 als Web-Framework, und ich werde die mitgelieferte Middleware Edge-Funktion verwenden
TailwindCss for Styling
Contentful CMS (Kostenloses Abo)
Vercel für das Hosting
Erweiterung des Content-Modells in Contentful
Bevor wir mit dem Programmieren beginnen, müssen wir das bestehende Inhaltsmodell für den Inhaltstyp „NavItem“ in Contentful anpassen. Wir werden 4 neue Attribute hinzufügen.
ShortDescription — Selbsterklärend
Icon — für das Symbol vor dem entsprechenden Menüpunkt
Type — Menu oder Submenu, damit man es im Code unterscheiden kann
SubMenuItems — Verlinkung der entsprechenden Untermenüpunkte

Anpassen der GraphQL-Abfrage für „NavItems“
Wir fügen die 4 neuen Felder in die Datei src/lib/graphql/navItemFields.graphql hinzu.
fragment NavItemFields on NavItem {
__typename
sys {
id
}
name
shortDescription
href
type
icon
subMenuItemsCollection {
items {
name
shortDescription
href
type
icon
}
}
}und dann führen wir diesen Befehl aus
npm run graphql-codegen:generateum die entsprechenden Dateien wie sdk.ts, graphql.schema.graphql und graphql.schema.json zu aktualisieren
Das Untermenü mit Contentful verbinden
Jetzt sind wir bereit für die Verbindung. Lassen Sie uns die Komponenten-Datei src/components/header/navbar.components.tsx anpassen.
//Line 39 we adapt the inteface
interface Linkitems {
key: number;
name: string;
shortDescription?: string;
href: string;
icon?: any;
submenutitems?: any;
breakpoint?: string;
}Neue Funktion für das Untermenü
function SubMenu({
href,
name,
shortDescription,
submenutitems,
breakpoint,
}: Linkitems) {
return (
<Popover className="relative">
<Popover.Button className="border-transparent text-gray-500 dark:text-gray-50 hover:border-gray-300 hover:text-gray-700 inline-flex items-center text-base px-1 pt-1 border-b-2 font-medium">
{breakpoint === "desktop" ? (
<>
<span>{name}</span>
<ChevronDownIcon className="w-5 h-5" aria-hidden="true" />
</>
) : (
<div className="pl-3 flex">
<span>{name}</span>
<ChevronDownIcon className="ml-2 w-5 h-5" aria-hidden="true" />
</div>
)}
</Popover.Button>
<Popover.Panel className="absolute left-1/2 z-10 mt-5 flex w-screen max-w-max -translate-x-1/2 px-4 transition data-[closed]:translate-y-1 data-[closed]:opacity-0 data-[enter]:duration-200 data-[leave]:duration-150 data-[enter]:ease-out data-[leave]:ease-in">
<div className="flex-auto w-screen max-w-md overflow-hidden text-sm leading-6 bg-white dark:bg-gray-500 shadow-lg rounded-3xl ring-1 ring-gray-900/5">
<div className="p-4">
{submenutitems.map((item: Linkitems) => (
<div
key={item.name}
className="relative flex p-4 rounded-lg group gap-x-6 hover:bg-gray-50"
>
<div className="flex items-center justify-center flex-none mt-1 rounded-lg h-11 w-11 bg-gray-50 group-hover:bg-white">
{item.icon === "BookmarkSquareIcon" ? (
<BookmarkSquareIcon
className="w-6 h-6 text-gray-600 group-hover:text-indigo-600"
aria-hidden="true"
/>
) : (
<LifebuoyIcon
className="w-6 h-6 text-gray-600 group-hover:text-indigo-600"
aria-hidden="true"
/>
)}
</div>
<div>
<a href={item.href} className="font-semibold text-gray-900">
{item.name}
<span className="absolute inset-0" />
</a>
<div className="mt-1 text-gray-800">
{item.shortDescription}
</div>
</div>
</div>
))}
</div>
</div>
</Popover.Panel>
</Popover>
);
}Änderungen - Desktop View und Mobile View
Desktop Ansicht — Wir verwenden eine bedingte Anweisung basierend auf dem Typ.
{/* Desktop View */}
{menuItems.map((menuItem: any, index: number) =>
menuItem.type === "Menu" ? (
<NavigationLink
key={index}
href={`/${locale}${menuItem.href}`}
name={menuItem.name}
/>
) : (
<SubMenu
key={index}
href={`/${locale}${menuItem.href}`}
name={menuItem.name}
submenutitems={menuItem.subMenuItemsCollection.items}
breakpoint="desktop"
/>
)
)} Mobile Ansicht — Hier verwenden wir ebenfalls eine bedingte Anweisung basierend auf dem Typ.
{/* Only show up in Mobile view */}
{menuItems.map((menuItem: any, index: number) =>
menuItem.type === "Menu" ? (
<NavigationLinkDisclosure
key={index}
href={`/${locale}${menuItem.href}`}
name={menuItem.name}
/>
) : (
<SubMenu
key={index}
href={`/${locale}${menuItem.href}`}
name={menuItem.name}
submenutitems={menuItem.subMenuItemsCollection.items}
breakpoint="mobile"
/>
)
)}Endergebnis
Unten befindet sich das Flyout-Menü, das die Daten von Contentful abruft und für den Desktop- und mobilen Breakpoint optimiert ist.

Cloudapp-dev und bevor Sie uns verlassen
Danke, dass Sie bis zum Ende gelesen haben. Noch eine Bitte bevor Sie gehen:



