refactor: cart button with icon
This commit is contained in:
parent
043cc4d11a
commit
d8e78b71e4
|
|
@ -0,0 +1,221 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Header": {
|
||||||
|
"config": {
|
||||||
|
"sticky": true
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"Banner": {
|
||||||
|
"config": {
|
||||||
|
"variant": "nav",
|
||||||
|
"className": "h-12 bg-[#E6EFFC] text-[#11314E] gap-12 pl-16",
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"Link": {
|
||||||
|
"config": {
|
||||||
|
"label": "Über Uns",
|
||||||
|
"href": "/",
|
||||||
|
"className": "text-[13px] flex items-center gap-1 cursor-pointer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Link": {
|
||||||
|
"config": {
|
||||||
|
"label": "Kontaktieren Uns",
|
||||||
|
"href": "/",
|
||||||
|
"className": "text-[13px] flex items-center gap-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
{
|
||||||
|
"Link": {
|
||||||
|
"config": {
|
||||||
|
"label": "Einsparung durch Digitalisierung in der Arztpraxis",
|
||||||
|
"href": "/",
|
||||||
|
"className": "text-[13px] flex items-center gap-1 "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Button": {
|
||||||
|
"config": {
|
||||||
|
"label": "Mehr Info",
|
||||||
|
"href": "/",
|
||||||
|
"className": "text-[13px] flex items-center bg-[#112638] gap-1 "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"Dropdown": {
|
||||||
|
"config": {
|
||||||
|
"trigger": {
|
||||||
|
"text": "EURO",
|
||||||
|
"className": "font-bold text-[13px] text-[#11314E] flex items-center gap-1 hover:text-[#009b93]",
|
||||||
|
"isShowArrow": true
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"icon": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Flag_of_Germany.svg/1200px-Flag_of_Germany.svg.png",
|
||||||
|
"text": "EURO",
|
||||||
|
"href": "/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VtCountryCodeSelect": {
|
||||||
|
"config": {
|
||||||
|
"trigger": {
|
||||||
|
"className": "w-auto font-bold text-[13px] text-[#11314E] flex justify-start items-center gap-1 hover:text-[#009b93] bg-transparent shadow-none hover:bg-transparent",
|
||||||
|
"isFlag": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Nav": {
|
||||||
|
"config": {
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"VtSideMenu": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VtMegaMenu": {
|
||||||
|
"config": {
|
||||||
|
"navLabel": {
|
||||||
|
"text": "Sale",
|
||||||
|
"className": "text-[13px] text-[#11314E] flex items-center mr-8 gap-1 hover:bg-transparent hover:underline hover:text-[#009b93]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
{
|
||||||
|
"HomeButton": {
|
||||||
|
"config": {
|
||||||
|
"label": "Medusa Store"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"AccountButton": {
|
||||||
|
"config": {
|
||||||
|
"label": "Account",
|
||||||
|
"className": "hover:text-ui-fg-base"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VtCartButton": {
|
||||||
|
"config": {
|
||||||
|
"variant": "link",
|
||||||
|
"className": "hover:text-ui-fg-base"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CartMismatchBanner": {
|
||||||
|
"config": {
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FreeShippingPriceNudge": {
|
||||||
|
"config": {
|
||||||
|
"variant": "popup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PropsChildren": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Footer": {
|
||||||
|
"config": {
|
||||||
|
"className": "content-container flex w-full border h-[300px] justify-between",
|
||||||
|
"left": [
|
||||||
|
{
|
||||||
|
"VtMenuItem": {
|
||||||
|
"config": {
|
||||||
|
"title": "category",
|
||||||
|
"className": "flex flex-col gap-y-2",
|
||||||
|
"itemClassName": "text-ui-fg-subtle txt-small ml-3",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"text": "Clothing",
|
||||||
|
"href": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Shoes",
|
||||||
|
"href": "/categories/shoes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Accessories",
|
||||||
|
"href": "/categories/accessories"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
{
|
||||||
|
"VtMenuItem": {
|
||||||
|
"config": {
|
||||||
|
"title": "category",
|
||||||
|
"className": "flex flex-col gap-y-2",
|
||||||
|
"itemClassName": "text-ui-fg-subtle txt-small ml-3",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"text": "Clothing",
|
||||||
|
"href": "/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Shoes",
|
||||||
|
"href": "/categories/shoes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Accessories",
|
||||||
|
"href": "/categories/accessories"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{
|
||||||
|
"Text": {
|
||||||
|
"config": {
|
||||||
|
"label": "Medusa Check",
|
||||||
|
"className": "text-[13px] text-[#A6A6A6]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { retrieveCart } from "@lib/data/cart"
|
import { retrieveCart } from "@lib/data/cart"
|
||||||
import CartDropdown from "../cart-dropdown"
|
import CartDropdown from "../cart-dropdown"
|
||||||
|
|
||||||
export default async function CartButton() {
|
export default async function CartButton({ iconName }: { iconName?: string }) {
|
||||||
const cart = await retrieveCart().catch(() => null)
|
const cart = await retrieveCart().catch(() => null)
|
||||||
|
|
||||||
return <CartDropdown cart={cart} />
|
return <CartDropdown cart={cart} iconName={iconName} />
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
import { convertToLocale } from "@lib/util/money"
|
import { convertToLocale } from "@lib/util/money"
|
||||||
import { HttpTypes } from "@medusajs/types"
|
import { HttpTypes } from "@medusajs/types"
|
||||||
import { Button } from "@medusajs/ui"
|
import { Button } from "@medusajs/ui"
|
||||||
|
import * as MedusaIcons from "@medusajs/icons"
|
||||||
import DeleteButton from "@modules/common/components/delete-button"
|
import DeleteButton from "@modules/common/components/delete-button"
|
||||||
import LineItemOptions from "@modules/common/components/line-item-options"
|
import LineItemOptions from "@modules/common/components/line-item-options"
|
||||||
import LineItemPrice from "@modules/common/components/line-item-price"
|
import LineItemPrice from "@modules/common/components/line-item-price"
|
||||||
|
|
@ -19,8 +20,10 @@ import { Fragment, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
const CartDropdown = ({
|
const CartDropdown = ({
|
||||||
cart: cartState,
|
cart: cartState,
|
||||||
|
iconName,
|
||||||
}: {
|
}: {
|
||||||
cart?: HttpTypes.StoreCart | null
|
cart?: HttpTypes.StoreCart | null
|
||||||
|
iconName?: string
|
||||||
}) => {
|
}) => {
|
||||||
const [activeTimer, setActiveTimer] = useState<NodeJS.Timer | undefined>(
|
const [activeTimer, setActiveTimer] = useState<NodeJS.Timer | undefined>(
|
||||||
undefined
|
undefined
|
||||||
|
|
@ -73,6 +76,10 @@ const CartDropdown = ({
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [totalItems, itemRef.current])
|
}, [totalItems, itemRef.current])
|
||||||
|
|
||||||
|
const Icon = iconName
|
||||||
|
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
|
||||||
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="h-full z-50"
|
className="h-full z-50"
|
||||||
|
|
@ -81,11 +88,15 @@ const CartDropdown = ({
|
||||||
>
|
>
|
||||||
<Popover className="relative h-full">
|
<Popover className="relative h-full">
|
||||||
<PopoverButton className="h-full">
|
<PopoverButton className="h-full">
|
||||||
<LocalizedClientLink
|
{Icon ? (
|
||||||
className="hover:text-ui-fg-base"
|
<Icon />
|
||||||
href="/cart"
|
) : (
|
||||||
data-testid="nav-cart-link"
|
<LocalizedClientLink
|
||||||
>{`Cart (${totalItems})`}</LocalizedClientLink>
|
className="hover:text-ui-fg-base"
|
||||||
|
href="/cart"
|
||||||
|
data-testid="nav-cart-link"
|
||||||
|
>{`Cart (${totalItems})`}</LocalizedClientLink>
|
||||||
|
)}
|
||||||
</PopoverButton>
|
</PopoverButton>
|
||||||
<Transition
|
<Transition
|
||||||
show={cartDropdownOpen}
|
show={cartDropdownOpen}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
||||||
import { LayoutComponentDefinition, LayoutContext } from "vibentec/component-map";
|
import {
|
||||||
|
LayoutComponentDefinition,
|
||||||
|
LayoutContext,
|
||||||
|
} from "vibentec/component-map"
|
||||||
import { clx } from "@medusajs/ui"
|
import { clx } from "@medusajs/ui"
|
||||||
|
import * as MedusaIcons from "@medusajs/icons"
|
||||||
export const AccountButton = ({ nodes, context }: { nodes: LayoutComponentDefinition; context: LayoutContext }) => {
|
export const AccountButton = ({
|
||||||
|
nodes,
|
||||||
|
context,
|
||||||
|
}: {
|
||||||
|
nodes: LayoutComponentDefinition
|
||||||
|
context: LayoutContext
|
||||||
|
}) => {
|
||||||
const props = nodes.config ?? {}
|
const props = nodes.config ?? {}
|
||||||
const className = clx("hover:text-ui-fg-base", props.className);
|
const className = clx("hover:text-ui-fg-base", props.className)
|
||||||
const style: React.CSSProperties = {};
|
const style: React.CSSProperties = {}
|
||||||
if (props.bgColor) style.backgroundColor = props.bgColor;
|
if (props.bgColor) style.backgroundColor = props.bgColor
|
||||||
if (props.textColor) style.color = props.textColor;
|
if (props.textColor) style.color = props.textColor
|
||||||
const href = props.href ?? "/account"
|
const href = props.href ?? "/account"
|
||||||
const label = props.label ?? "Account"
|
const label = props.label ?? "Account"
|
||||||
|
const iconName = props.icon
|
||||||
|
const Icon = iconName
|
||||||
|
? (MedusaIcons as Record<string, React.ComponentType<any>>)[iconName]
|
||||||
|
: undefined
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center h-full" style={style}>
|
<div className="flex items-center h-full">
|
||||||
<LocalizedClientLink
|
<LocalizedClientLink
|
||||||
href={href}
|
href={href}
|
||||||
className={className}
|
className={className}
|
||||||
data-testid="nav-account-link"
|
data-testid="nav-account-link"
|
||||||
>
|
>
|
||||||
{label}
|
{Icon ? <Icon /> : label}
|
||||||
</LocalizedClientLink>
|
</LocalizedClientLink>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,9 @@ import {
|
||||||
LayoutComponentDefinition,
|
LayoutComponentDefinition,
|
||||||
LayoutContext,
|
LayoutContext,
|
||||||
} from "vibentec/component-map"
|
} from "vibentec/component-map"
|
||||||
import { clx, IconButton } from "@medusajs/ui"
|
import { clx } from "@medusajs/ui"
|
||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
import CartButton from "@modules/layout/components/cart-button"
|
import CartButton from "@modules/layout/components/cart-button"
|
||||||
import { ShoppingBag, ShoppingCart } from "@medusajs/icons"
|
|
||||||
|
|
||||||
const IconButtonComponent = ({ className, variant }: { className?: string; variant?: "shoppingBag" | "cart" }) => {
|
|
||||||
const variants = {
|
|
||||||
shoppingBag: ShoppingBag,
|
|
||||||
cart: ShoppingCart,
|
|
||||||
}
|
|
||||||
const Icon = variants[variant ?? "shoppingBag"]
|
|
||||||
return (
|
|
||||||
<IconButton className={className}>
|
|
||||||
<Icon />
|
|
||||||
</IconButton>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VtCartButton = ({
|
export const VtCartButton = ({
|
||||||
nodes,
|
nodes,
|
||||||
|
|
@ -30,15 +16,6 @@ export const VtCartButton = ({
|
||||||
}) => {
|
}) => {
|
||||||
const props = nodes.config ?? {}
|
const props = nodes.config ?? {}
|
||||||
const className = clx("hover:text-ui-fg-base flex gap-2", props.className)
|
const className = clx("hover:text-ui-fg-base flex gap-2", props.className)
|
||||||
|
|
||||||
const variants = {
|
|
||||||
link: <CartButton />,
|
|
||||||
shoppingBagbutton: <IconButtonComponent className={className} variant="shoppingBag" />,
|
|
||||||
cartIconButton: <IconButtonComponent className={className} variant="cart" />,
|
|
||||||
}
|
|
||||||
if (!props.variant) return null
|
|
||||||
const fallBackComp = variants[props.variant as keyof typeof variants]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
|
|
@ -51,7 +28,7 @@ export const VtCartButton = ({
|
||||||
</LocalizedClientLink>
|
</LocalizedClientLink>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{fallBackComp}
|
<CartButton iconName={props.icon} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue