feat: create components and map with data json file of 3bear design
This commit is contained in:
@@ -1,13 +1,38 @@
|
||||
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
||||
import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map";
|
||||
import { clx } from "@medusajs/ui"
|
||||
import { Suspense } from "react";
|
||||
import CartButton from "@modules/layout/components/cart-button";
|
||||
|
||||
export const VtCartButton = ({ nodes, context }: { nodes: LayoutComponentDefinition; context: LayoutContext }) => {
|
||||
import {
|
||||
LayoutComponentDefinition,
|
||||
LayoutContext,
|
||||
} from "vibentec/component-map"
|
||||
import { clx, IconButton } from "@medusajs/ui"
|
||||
import { Suspense } from "react"
|
||||
import CartButton from "@modules/layout/components/cart-button"
|
||||
import { ShoppingBag } from "@medusajs/icons"
|
||||
|
||||
const CartIconButtonComponent = ({ className }: { className?: string }) => {
|
||||
return (
|
||||
<IconButton className={className}>
|
||||
<ShoppingBag />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
|
||||
export const VtCartButton = ({
|
||||
nodes,
|
||||
context,
|
||||
}: {
|
||||
nodes: LayoutComponentDefinition
|
||||
context: LayoutContext
|
||||
}) => {
|
||||
const props = nodes.config ?? {}
|
||||
const className = clx("hover:text-ui-fg-base flex gap-2", props.className)
|
||||
|
||||
const variants = {
|
||||
link: <CartButton />,
|
||||
button: <CartIconButtonComponent className={className} />,
|
||||
}
|
||||
if (!props.variant) return null
|
||||
const fallBackComp = variants[props.variant as keyof typeof variants]
|
||||
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
@@ -20,9 +45,9 @@ export const VtCartButton = ({ nodes, context }: { nodes: LayoutComponentDefinit
|
||||
</LocalizedClientLink>
|
||||
}
|
||||
>
|
||||
<CartButton />
|
||||
{fallBackComp}
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
export default VtCartButton
|
||||
export default VtCartButton
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"use client"
|
||||
import { DropdownMenu } from "@medusajs/ui"
|
||||
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
||||
import ChevronDown from "@modules/common/icons/chevron-down"
|
||||
import {
|
||||
LayoutComponentDefinition,
|
||||
LayoutContext,
|
||||
} from "@vibentec/component-map"
|
||||
|
||||
export default function VtDropdown({
|
||||
nodes,
|
||||
context,
|
||||
}: {
|
||||
nodes: LayoutComponentDefinition
|
||||
context: LayoutContext
|
||||
}) {
|
||||
const props = nodes.config ?? {}
|
||||
if (!props.trigger.text || props.items.length === 0) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenu.Trigger
|
||||
className={props.trigger.className + " flex items-center gap-1"}
|
||||
>
|
||||
{props.trigger.icon && (
|
||||
<img
|
||||
src={props.trigger.icon}
|
||||
alt={props.trigger.text}
|
||||
className="w-5 h-5 rounded-[50%] mr-3"
|
||||
/>
|
||||
)}
|
||||
{props.trigger.text} {props.trigger.isShowArrow && <ChevronDown />}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
{props.items.map(
|
||||
(
|
||||
item: {
|
||||
text: string
|
||||
className?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
},
|
||||
index: number
|
||||
) => (
|
||||
<DropdownMenu.Item
|
||||
key={item.text + index}
|
||||
className={item.className || ""}
|
||||
>
|
||||
{item.icon && (
|
||||
<img
|
||||
src={item.icon}
|
||||
alt={item.text}
|
||||
className="w-5 h-5 rounded-[50%] mr-3"
|
||||
/>
|
||||
)}
|
||||
{item.href ? (
|
||||
<LocalizedClientLink href={item.href}>
|
||||
{item.text}
|
||||
</LocalizedClientLink>
|
||||
) : (
|
||||
item.text
|
||||
)}
|
||||
</DropdownMenu.Item>
|
||||
)
|
||||
)}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +1,34 @@
|
||||
import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map";
|
||||
import React, { Suspense } from "react";
|
||||
import SkeletonMegaMenu from "@modules/skeletons/components/vt-skeleton-mega-menu";
|
||||
import MegaMenuWrapper from "@modules/layout/components/vt-mega-menu/mega-menu-wrapper";
|
||||
import {
|
||||
LayoutComponentDefinition,
|
||||
LayoutContext,
|
||||
} from "vibentec/component-map"
|
||||
import React, { Suspense } from "react"
|
||||
import SkeletonMegaMenu from "@modules/skeletons/components/vt-skeleton-mega-menu"
|
||||
import MegaMenuWrapper from "@modules/layout/components/vt-mega-menu/mega-menu-wrapper"
|
||||
|
||||
export default function VtMegaMenu({ nodes, context }: { nodes: LayoutComponentDefinition; context: LayoutContext }) {
|
||||
interface MegaMenuProps {
|
||||
navLabel: {
|
||||
text: string
|
||||
className?: string
|
||||
}
|
||||
}
|
||||
export default function VtMegaMenu({
|
||||
nodes,
|
||||
context,
|
||||
}: {
|
||||
nodes: LayoutComponentDefinition
|
||||
context: LayoutContext
|
||||
}) {
|
||||
const { navLabel } = nodes.config as MegaMenuProps ?? {}
|
||||
return (
|
||||
<nav>
|
||||
<ul className="space-x-4 hidden small:flex">
|
||||
<li>
|
||||
<Suspense fallback={<SkeletonMegaMenu />}>
|
||||
<MegaMenuWrapper />
|
||||
<MegaMenuWrapper navLabel={navLabel} />
|
||||
</Suspense>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { listCategories } from "@lib/data/categories"
|
||||
import MegaMenu from "./mega-menu"
|
||||
|
||||
export async function MegaMenuWrapper() {
|
||||
|
||||
|
||||
export async function MegaMenuWrapper({ navLabel }: { navLabel: { text: string; className?: string } }) {
|
||||
const categories = await listCategories().catch(() => [])
|
||||
|
||||
return <MegaMenu categories={categories} />
|
||||
return <MegaMenu navLabel={navLabel} categories={categories} />
|
||||
}
|
||||
|
||||
export default MegaMenuWrapper
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { clx } from "@medusajs/ui"
|
||||
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
||||
import ChevronDown from "@modules/common/icons/chevron-down"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
|
||||
const MegaMenu = ({
|
||||
navLabel,
|
||||
categories,
|
||||
}: {
|
||||
navLabel: { text: string; className?: string, isShowArrow?: boolean },
|
||||
categories: HttpTypes.StoreProductCategory[]
|
||||
}) => {
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
@@ -81,10 +85,13 @@ const MegaMenu = ({
|
||||
className="z-50"
|
||||
>
|
||||
<LocalizedClientLink
|
||||
className="hover:text-ui-fg-base hover:bg-neutral-100 rounded-full px-3 py-2"
|
||||
className={clx(
|
||||
"hover:text-ui-fg-base hover:bg-neutral-100 rounded-full px-3 py-2",
|
||||
navLabel.className
|
||||
)}
|
||||
href="/store"
|
||||
>
|
||||
Products
|
||||
{navLabel.text} {navLabel.isShowArrow && <ChevronDown />}
|
||||
</LocalizedClientLink>
|
||||
{isHovered && (
|
||||
<div className="absolute top-full left-0 right-0 flex gap-32 py-10 px-20 bg-white border-b border-neutral-200 ">
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { IconButton } from "@medusajs/ui"
|
||||
import { MagnifyingGlass, User, ShoppingBag } from "@medusajs/icons"
|
||||
import {
|
||||
LayoutComponentDefinition,
|
||||
LayoutContext,
|
||||
} from "@vibentec/component-map"
|
||||
|
||||
export default function VtIconButton({
|
||||
nodes,
|
||||
context,
|
||||
}: {
|
||||
nodes: LayoutComponentDefinition
|
||||
context: LayoutContext
|
||||
}) {
|
||||
const props = nodes.config || {}
|
||||
const variantsIcon = {
|
||||
search: MagnifyingGlass,
|
||||
user: User,
|
||||
cart: ShoppingBag
|
||||
}
|
||||
if (!props.variant) return null
|
||||
const Icon = variantsIcon[props.variant as keyof typeof variantsIcon]
|
||||
return (
|
||||
<IconButton className={props?.className ?? ""}>
|
||||
<Icon />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
@@ -51,7 +51,8 @@
|
||||
|
||||
@layer components {
|
||||
.content-container {
|
||||
@apply max-w-[1440px] w-full mx-auto px-6;
|
||||
/* @apply max-w-[1440px] w-full mx-auto px-6; */
|
||||
@apply w-full mx-auto px-6;
|
||||
}
|
||||
|
||||
.contrast-btn {
|
||||
@@ -110,3 +111,6 @@
|
||||
@apply text-[32px] leading-[44px] font-semibold;
|
||||
}
|
||||
}
|
||||
[data-radix-popper-content-wrapper]{
|
||||
z-index: 51 !important;
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import VtMegaMenu from "@modules/layout/components/vt-mega-menu"
|
||||
import VtLink from "@modules/layout/components/vt-linkbutton"
|
||||
import VtSideMenu from "@modules/layout/components/vt-sidemenu"
|
||||
import VtImage from "@modules/layout/templates/vt-image"
|
||||
import VtDropdown from "@modules/layout/components/vt-dropdown"
|
||||
import VtIconButton from "@modules/layout/templates/vt-icon-button"
|
||||
|
||||
type ComponentConfig = Record<string, any>;
|
||||
|
||||
@@ -54,9 +56,11 @@ export const componentMap: Record<string, ComponentRenderer> = {
|
||||
Banner: nodesContextRenderer(Banner),
|
||||
HomeButton: nodesContextRenderer(HomeButton),
|
||||
AccountButton: nodesContextRenderer(AccountButton),
|
||||
IconButton: nodesContextRenderer(VtIconButton),
|
||||
VtCartButton: nodesContextRenderer(VtCartButton),
|
||||
Link: nodesContextRenderer(VtLink),
|
||||
Image: nodesContextRenderer(VtImage),
|
||||
Dropdown: nodesContextRenderer(VtDropdown),
|
||||
CartMismatchBanner: configOnly(CartMismatchBanner),
|
||||
FreeShippingPriceNudge: configOnly(FreeShippingPriceNudge),
|
||||
PropsChildren: {
|
||||
|
||||
Reference in New Issue
Block a user