mirror of
https://github.com/vercel/commerce.git
synced 2025-06-16 04:11:22 +00:00
Update the query and ui to show the subitem of the menu
This commit is contained in:
parent
c799a5f53d
commit
6f16b74580
20
components/MegaMenu/mega-meu.tsx
Normal file
20
components/MegaMenu/mega-meu.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { MenuItem } from '../../lib/shopify/types';
|
||||
import MenuItemComponent from './menu-item-component';
|
||||
|
||||
type MegaMenuProps = {
|
||||
menu: MenuItem[];
|
||||
};
|
||||
|
||||
const MegaMenu = ({ menu }: MegaMenuProps) => {
|
||||
return (
|
||||
<div className="mt-4 hidden justify-center md:flex">
|
||||
<ul className="text-md flex gap-6 font-semibold">
|
||||
{menu.map((item) => (
|
||||
<MenuItemComponent key={item.title} item={item} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MegaMenu;
|
38
components/MegaMenu/menu-item-component.tsx
Normal file
38
components/MegaMenu/menu-item-component.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import Link from 'next/link';
|
||||
import { MenuItem } from '../../lib/shopify/types';
|
||||
|
||||
type MenuItemProps = {
|
||||
item: MenuItem;
|
||||
isSubMenu?: boolean;
|
||||
};
|
||||
|
||||
const MenuItemComponent = ({ item, isSubMenu = false }: MenuItemProps) => {
|
||||
return (
|
||||
<li className={`group relative ${isSubMenu ? 'submenu-item p-2' : ''}`}>
|
||||
<Link
|
||||
href={item.path}
|
||||
className="pl-2 font-semibold text-neutral-500 underline-offset-4 hover:text-black hover:underline dark:text-neutral-400 dark:hover:text-neutral-300"
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
{item.items.length > 0 && (
|
||||
<ul className="absolute left-0 top-full z-10 hidden w-48 rounded-xl bg-white shadow-lg group-hover:block">
|
||||
{item.items.map((subItem) => (
|
||||
<MenuItemComponent key={subItem.title} item={subItem} isSubMenu={true} />
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{isSubMenu && item.items.length > 0 && (
|
||||
<ul className="absolute left-0 top-full z-10 hidden w-48 bg-white shadow-lg group-hover:block">
|
||||
{item.items.map((subItem, index) =>
|
||||
index === 2 ? (
|
||||
<MenuItemComponent key={subItem.title} item={subItem} isSubMenu={true} />
|
||||
) : null
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export default MenuItemComponent;
|
@ -1,9 +1,8 @@
|
||||
import MegaMenu from 'components/MegaMenu/mega-meu';
|
||||
import Cart from 'components/cart';
|
||||
import OpenCart from 'components/cart/open-cart';
|
||||
import LogoSquare from 'components/logo-square';
|
||||
import { getMenu } from 'lib/shopify';
|
||||
import { Menu } from 'lib/shopify/types';
|
||||
import { RemoveTheDomainFromUrl } from 'lib/utils';
|
||||
import { getMegaMenu } from 'lib/shopify';
|
||||
import Link from 'next/link';
|
||||
import { Suspense } from 'react';
|
||||
import MobileMenu from './mobile-menu';
|
||||
@ -11,10 +10,11 @@ import Search, { SearchSkeleton } from './search';
|
||||
const { SITE_NAME } = process.env;
|
||||
|
||||
export default async function Navbar() {
|
||||
const menu = await getMenu('next-js-frontend-header-menu');
|
||||
const menu = await getMegaMenu('next-js-frontend-header-menu');
|
||||
|
||||
return (
|
||||
<nav className="relative flex items-center justify-between p-4 lg:px-6">
|
||||
<nav className="relative mx-auto max-w-screen-2xl p-4 lg:px-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="block flex-none md:hidden">
|
||||
<Suspense fallback={null}>
|
||||
<MobileMenu menu={menu} />
|
||||
@ -22,26 +22,15 @@ export default async function Navbar() {
|
||||
</div>
|
||||
<div className="flex w-full items-center">
|
||||
<div className="flex w-full md:w-1/3">
|
||||
<Link href="/" className="mr-2 flex w-full items-center justify-center md:w-auto lg:mr-6">
|
||||
<Link
|
||||
href="/"
|
||||
className="mr-2 flex w-full items-center justify-center md:w-auto lg:mr-6"
|
||||
>
|
||||
<LogoSquare />
|
||||
<div className="ml-2 flex-none text-sm font-medium uppercase md:hidden lg:block">
|
||||
{SITE_NAME}
|
||||
</div>
|
||||
</Link>
|
||||
{menu.length ? (
|
||||
<ul className="hidden gap-6 text-sm md:flex md:items-center">
|
||||
{menu.map((item: Menu) => (
|
||||
<li key={item.title}>
|
||||
<Link
|
||||
href={RemoveTheDomainFromUrl(item.path)}
|
||||
className="text-neutral-500 underline-offset-4 hover:text-black hover:underline dark:text-neutral-400 dark:hover:text-neutral-300"
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="hidden justify-center md:flex md:w-1/3">
|
||||
<Suspense fallback={<SearchSkeleton />}>
|
||||
@ -54,6 +43,8 @@ export default async function Navbar() {
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{menu.length ? <MegaMenu menu={menu} /> : null}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import {
|
||||
Connection,
|
||||
Image,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Page,
|
||||
Product,
|
||||
ShopifyAddToCartOperation,
|
||||
@ -354,6 +355,30 @@ export async function getMenu(handle: string): Promise<Menu[]> {
|
||||
);
|
||||
}
|
||||
|
||||
export async function getMegaMenu(handle: string): Promise<MenuItem[]> {
|
||||
const res = await shopifyFetch<ShopifyMenuOperation>({
|
||||
query: getMenuQuery,
|
||||
tags: [TAGS.collections],
|
||||
variables: {
|
||||
handle
|
||||
}
|
||||
});
|
||||
|
||||
// Function to map the menu items and their nested items
|
||||
const mapMenuItems = (items: any): MenuItem[] => {
|
||||
console.log(items);
|
||||
return items.map((item: any) => ({
|
||||
title: item.title,
|
||||
path: item.url
|
||||
? item.url.replace(domain, '').replace('/collections', '/search').replace('/pages', '')
|
||||
: '',
|
||||
items: item.items ? mapMenuItems(item.items) : []
|
||||
}));
|
||||
};
|
||||
|
||||
return res.body?.data?.menu?.items ? mapMenuItems(res.body.data.menu.items) : [];
|
||||
}
|
||||
|
||||
export async function getPage(handle: string): Promise<Page> {
|
||||
const res = await shopifyFetch<ShopifyPageOperation>({
|
||||
query: getPageQuery,
|
||||
|
@ -4,6 +4,14 @@ export const getMenuQuery = /* GraphQL */ `
|
||||
items {
|
||||
title
|
||||
url
|
||||
items {
|
||||
title
|
||||
url
|
||||
items {
|
||||
title
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,14 @@ export type Menu = {
|
||||
path: string;
|
||||
};
|
||||
|
||||
export interface MenuItem {
|
||||
title: string;
|
||||
path: string;
|
||||
items: MenuItem[];
|
||||
}
|
||||
|
||||
export type MegaMenu = MenuItem[];
|
||||
|
||||
export type Money = {
|
||||
amount: string;
|
||||
currencyCode: string;
|
||||
|
19
lib/utils.ts
19
lib/utils.ts
@ -1,5 +1,4 @@
|
||||
import { ReadonlyURLSearchParams } from 'next/navigation';
|
||||
const { SHOPIFY_STORE_DOMAIN } = process.env;
|
||||
|
||||
export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => {
|
||||
const paramsString = params.toString();
|
||||
@ -8,24 +7,6 @@ export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyUR
|
||||
return `${pathname}${queryString}`;
|
||||
};
|
||||
|
||||
export const RemoveTheDomainFromUrl = (url: string) => {
|
||||
const lowercaseString = `https://${SHOPIFY_STORE_DOMAIN}`.toLowerCase();
|
||||
const modifiedUrl = url.replace(lowercaseString, '');
|
||||
|
||||
return modifiedUrl;
|
||||
};
|
||||
|
||||
export const RemoveTheDomainFromArray = (menu: any) => {
|
||||
const lowercaseString = `https://${SHOPIFY_STORE_DOMAIN}`.toLowerCase();
|
||||
|
||||
const modifiedUrls = menu.map((item: any) => {
|
||||
const modifiedPath = item.path.replace(lowercaseString, '');
|
||||
return { ...item, path: modifiedPath };
|
||||
});
|
||||
|
||||
return modifiedUrls;
|
||||
};
|
||||
|
||||
export const ensureStartsWith = (stringToCheck: string, startsWith: string) =>
|
||||
stringToCheck.startsWith(startsWith) ? stringToCheck : `${startsWith}${stringToCheck}`;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user