feat: create navigation menu for 3bear design
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
"use client"
|
||||
import * as React from "react"
|
||||
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
||||
import { clx } from "@medusajs/ui"
|
||||
import { ChevronDownMini } from "@medusajs/icons"
|
||||
|
||||
interface NavigationMenuProps {
|
||||
props: {
|
||||
label: string,
|
||||
className: string,
|
||||
"data-testid": string,
|
||||
isShowArrow: boolean
|
||||
},
|
||||
menuItems: MenuSection[]
|
||||
}
|
||||
type MenuSection = {
|
||||
title: { text: string; className?: string }
|
||||
links: MenuLink[]
|
||||
}
|
||||
type MenuLink = { label: string; href: string; className?: string }
|
||||
|
||||
// Structured menu data used to map UI
|
||||
const menuSections: MenuSection[] = [
|
||||
{
|
||||
title: { text: "Categories", className: "text-red" },
|
||||
links: [
|
||||
{
|
||||
label: "Overnight Oats",
|
||||
href: "/categories/overnight-oats",
|
||||
className: "text-red",
|
||||
},
|
||||
{ label: "Porridge", href: "/categories/porridge" },
|
||||
{ label: "Cereals", href: "/categories/cereals" },
|
||||
{ label: "Granola", href: "/categories/granola" },
|
||||
{ label: "Glasses & Bowls", href: "/categories/glasses-bowls" },
|
||||
{ label: "Oat Bars", href: "/categories/oat-bars" },
|
||||
{ label: "Nut butters", href: "/categories/nut-butters" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: { text: "Specials" },
|
||||
links: [
|
||||
{ label: "Advent calendar ✨", href: "/collections/advent-calendar" },
|
||||
{ label: "Saver subscription", href: "/collections/saver-subscription" },
|
||||
{ label: "bestseller", href: "/collections/bestseller" },
|
||||
{ label: "New 🔥", href: "/collections/new" },
|
||||
{ label: "Bluey Kidsrange", href: "/collections/bluey-kidsrange" },
|
||||
{ label: "Value sets", href: "/collections/value-sets" },
|
||||
{ label: "Sale", href: "/collections/sale" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: { text: "All products" },
|
||||
links: [{ label: "Shop all", href: "/store" }],
|
||||
},
|
||||
]
|
||||
|
||||
const MenuLinkItem = ({ href, label, className }: MenuLink) => (
|
||||
<li key={label}>
|
||||
<LocalizedClientLink
|
||||
href={href}
|
||||
className={clx(
|
||||
"block rounded-md py-2 hover:bg-ui-bg-subtle ",
|
||||
className ?? ""
|
||||
)}
|
||||
role="menuitem"
|
||||
>
|
||||
<div className="txt-small text-ui-fg-muted">{label}</div>
|
||||
</LocalizedClientLink>
|
||||
</li>
|
||||
)
|
||||
|
||||
const MenuSectionItem = ({ title, links }: MenuSection) => (
|
||||
<div key={title.text} className="space-y-1">
|
||||
<div className={clx("txt-small text-ui-fg-muted", title.className ?? "")}>
|
||||
{title.text}
|
||||
</div>
|
||||
<ul className="space-y-1">
|
||||
{links.map((link) => (
|
||||
<MenuLinkItem
|
||||
key={link.label}
|
||||
href={link.href}
|
||||
label={link.label}
|
||||
className={link.className ?? ""}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
export default function NavigationMenu({
|
||||
props,
|
||||
menuItems = menuSections,
|
||||
}: NavigationMenuProps) {
|
||||
return (
|
||||
<div className="group relative h-full flex items-center">
|
||||
<LocalizedClientLink
|
||||
href="/"
|
||||
className="txt-compact-xlarge-plus text-ui-fg-subtle hover:text-ui-fg-base group-hover:text-ui-fg-base flex items-center gap-2 transition-colors duration-200"
|
||||
>
|
||||
{props.label} {props?.isShowArrow ? (
|
||||
<span className="transition-transform duration-400 ease-out group-hover:rotate-180">
|
||||
<ChevronDownMini />
|
||||
</span>
|
||||
) : null}
|
||||
</LocalizedClientLink>
|
||||
|
||||
<div
|
||||
role="menu"
|
||||
className="pointer-events-none left-0 fixed top-[180px] invisible opacity-0 transform-gpu translate-y-2 transition-all duration-600 ease-out group-hover:visible group-hover:opacity-100 group-hover:translate-y-0 group-hover:pointer-events-auto group-focus-within:visible group-focus-within:opacity-100 group-focus-within:translate-y-0 group-focus-within:pointer-events-auto"
|
||||
>
|
||||
<div className="w-[100vw] bg-white shadow-borders-base py-4 px-20">
|
||||
<div className="grid grid-cols-1 small:grid-cols-3 gap-6">
|
||||
{menuItems.map((section) => (
|
||||
<MenuSectionItem
|
||||
key={section.title.text}
|
||||
title={section.title}
|
||||
links={section.links}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export default async function VtNav({ nodes, context, className }: DynamicLayout
|
||||
const regions = await listRegions().then((regions: StoreRegion[]) => regions)
|
||||
|
||||
return (
|
||||
<div className="sticky top-0 inset-x-0 z-50 group">
|
||||
<div className="sticky top-[40px] inset-x-0 z-50">
|
||||
<header className={clx("relative mx-auto border-b duration-200 border-ui-border-base", className ?? "bg-white") }>
|
||||
<nav className="flex justify-between w-full items-center h-full">
|
||||
{/* <div className="flex-1 basis-0 h-full flex items-center">
|
||||
|
||||
@@ -14,6 +14,7 @@ import { User, MagnifyingGlassMini, Heart } from "@medusajs/icons"
|
||||
import DropdownMenuComponent from "@modules/layout/templates/dropdown-menu/dropdown-menu"
|
||||
import AnnouncementBannerVibenTec from "@modules/layout/templates/vibentec-template/announcement-bar"
|
||||
import SearchButton from "@modules/layout/components/search-button"
|
||||
import NavigationMenu from "@modules/layout/components/navigation-menu"
|
||||
|
||||
export interface LayoutComponentDefinition {
|
||||
props?: Record<string, any>
|
||||
@@ -92,6 +93,11 @@ export const componentMap: Record<string, ComponentRenderer> = {
|
||||
<DropdownMenuComponent {...entry} />
|
||||
),
|
||||
},
|
||||
NavMenu: {
|
||||
render: (entry: any, ctx: LayoutContext) => (
|
||||
<NavigationMenu props={entry.props} menuItems={entry.menuItems} />
|
||||
),
|
||||
},
|
||||
LocalizedClientLink: {
|
||||
render: (entry: any) => (
|
||||
<LocalizedClientLink {...entry.props}>
|
||||
|
||||
Reference in New Issue
Block a user