x
This commit is contained in:
1 parent
f6c188bd93
commit
b78c9467bc
9 files changed
+656
-49
No files matched your search
@@ -5,19 +5,24 @@ import Image from 'next/image'
|
||||
import { useState, useRef } from 'react'
|
||||
import {
|
||||
ArrowRight,
|
||||
Award,
|
||||
Box,
|
||||
ChevronRight,
|
||||
Gift,
|
||||
Leaf,
|
||||
Package,
|
||||
ShoppingBag,
|
||||
Sparkles,
|
||||
Star,
|
||||
type LucideIcon,
|
||||
Sparkles,
|
||||
Box,
|
||||
} from 'lucide-react'
|
||||
import type { MegaMenuPayload, MenuColumn } from './menuTypes'
|
||||
import { getLocalizedMenuText } from './menuTypes'
|
||||
import { ICON_REGISTRY, type AvailableIcons } from './iconRegistry'
|
||||
|
||||
function DynamicIcon({ iconName, defaultIcon: DefaultIcon, className, strokeWidth }: { iconName?: string, defaultIcon: any, className?: string, strokeWidth?: number }) {
|
||||
const IconComponent = (iconName && ICON_REGISTRY[iconName as AvailableIcons])
|
||||
? ICON_REGISTRY[iconName as AvailableIcons]
|
||||
: DefaultIcon;
|
||||
|
||||
return <IconComponent className={className} strokeWidth={strokeWidth} />;
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface DesktopMegaMenuProps {
|
||||
items: MegaMenuPayload[]
|
||||
@@ -25,14 +30,7 @@ interface DesktopMegaMenuProps {
|
||||
currentPath: string
|
||||
}
|
||||
|
||||
const MENU_ICONS: LucideIcon[] = [
|
||||
ShoppingBag,
|
||||
Sparkles,
|
||||
Leaf,
|
||||
Package,
|
||||
Gift,
|
||||
Award,
|
||||
]
|
||||
|
||||
|
||||
const MAX_TOP_LEVEL_LINKS = 5
|
||||
const MAX_INLINE_CHILD_LINKS = 3
|
||||
@@ -52,11 +50,13 @@ function MenuImage({
|
||||
alt,
|
||||
placeholder,
|
||||
className = '',
|
||||
style,
|
||||
}: {
|
||||
src?: string | null
|
||||
alt: string
|
||||
placeholder?: string
|
||||
className?: string
|
||||
style?: React.CSSProperties
|
||||
}) {
|
||||
const [loaded, setLoaded] = useState(false)
|
||||
|
||||
@@ -74,6 +74,7 @@ function MenuImage({
|
||||
fill
|
||||
sizes="(max-width: 1024px) 0px, 224px"
|
||||
className={`object-cover transition-opacity duration-300 ${loaded ? 'opacity-100' : 'opacity-0'} ${className}`}
|
||||
style={style}
|
||||
onLoad={() => setLoaded(true)}
|
||||
loading="lazy"
|
||||
/>
|
||||
@@ -120,6 +121,8 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro
|
||||
const showFeatured = featuredConfig?.enabled !== false
|
||||
const configuredImage = featuredConfig?.imageUrl || null
|
||||
const featuredImage = hoveredLinkImage ?? configuredImage ?? featuredLink?.imageUrl ?? item.rootImageUrl
|
||||
const focalPoint = featuredConfig?.focalPoint
|
||||
const objectPosition = focalPoint ? `${focalPoint.x} ${focalPoint.y}` : 'center'
|
||||
const featuredHeading = getLocalizedMenuText(featuredConfig?.sectionTitle, lang) || 'Featured'
|
||||
const featuredBadge = getLocalizedMenuText(featuredConfig?.badge, lang) || 'Recommended'
|
||||
const featuredTitle = getLocalizedMenuText(featuredConfig?.title, lang)
|
||||
@@ -179,15 +182,16 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro
|
||||
className={`pr-8 ${columnIndex > 0 ? 'border-l border-line-primary/15 pl-8' : ''}`}
|
||||
>
|
||||
<h4 className="mb-5 flex items-center gap-3 text-xs font-bold normal-case tracking-normal text-text-main">
|
||||
{(() => {
|
||||
const HeadingIcon = MENU_ICONS[columnIndex] ?? Sparkles
|
||||
return <HeadingIcon className="h-4 w-4 text-brand-primary" strokeWidth={1.5} />
|
||||
})()}
|
||||
<DynamicIcon
|
||||
iconName={column.icon}
|
||||
defaultIcon={Sparkles}
|
||||
className="h-4 w-4 text-brand-primary"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
{getLocalizedMenuText(column.title, lang)}
|
||||
</h4>
|
||||
<ul className="space-y-2">
|
||||
{column.links.slice(0, MAX_TOP_LEVEL_LINKS).map((link, linkIndex) => {
|
||||
const RowIcon = MENU_ICONS[(columnIndex * 3 + linkIndex + 1) % MENU_ICONS.length] ?? Box
|
||||
const hasNestedLinks = !!link.links?.length
|
||||
const visibleChildLinks = link.links?.slice(0, MAX_INLINE_CHILD_LINKS) ?? []
|
||||
const hiddenChildCount = Math.max((link.links?.length ?? 0) - MAX_INLINE_CHILD_LINKS, 0)
|
||||
@@ -205,7 +209,12 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro
|
||||
className="group flex items-center gap-4 rounded-md px-1 py-2.5 text-left transition-colors hover:bg-surface-muted"
|
||||
>
|
||||
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md border border-line-primary/20 bg-surface-page text-brand-primary transition-colors group-hover:border-brand-primary/40">
|
||||
<RowIcon className="h-5 w-5" strokeWidth={1.35} />
|
||||
<DynamicIcon
|
||||
iconName={link.icon}
|
||||
defaultIcon={Box}
|
||||
className="h-5 w-5"
|
||||
strokeWidth={1.35}
|
||||
/>
|
||||
</span>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block text-sm font-bold normal-case tracking-normal text-text-main">
|
||||
@@ -275,6 +284,8 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro
|
||||
src={featuredImage}
|
||||
alt={featuredTitle}
|
||||
placeholder={getLocalizedMenuText(item.label, lang)}
|
||||
className="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
|
||||
style={{ objectPosition }}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2 p-4">
|
||||
|
||||
Reference in new issue
Block a user