Loading...
Flyout part2
Author Cloudapp
E.G.

Next.js 14 - Flyout-Menüs mit TailwindCSS & Contentful - Teil 2

23. Juli 2024
Inhaltsverzeichnis

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.

  1. ShortDescription — Selbsterklärend

  2. Icon — für das Symbol vor dem entsprechenden Menüpunkt

  3. Type — Menu oder Submenu, damit man es im Code unterscheiden kann

  4. SubMenuItems — Verlinkung der entsprechenden Untermenüpunkte

Nav-item-content-model
Nav-item-content-model

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:generate

um 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.

Cut Menu example
Cut Menu example

Cloudapp-dev und bevor Sie uns verlassen

Danke, dass Sie bis zum Ende gelesen haben. Noch eine Bitte bevor Sie gehen:

Wenn Ihnen gefallen hat was Sie gelesen haben oder wenn es Ihnen sogar geholfen hat, dann würden wir uns über einen "Clap" 👏 oder einen neuen Follower auf unseren Medium Account sehr freuen.

Oder folgen Sie uns auf Twitter -> Cloudapp.dev

Verwandte Artikel