173 lines
5.6 KiB
TypeScript
173 lines
5.6 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
import { MEGA_MENU_TABS } from "@/data/home";
|
|
|
|
export type MegaColumn = {
|
|
title: string;
|
|
href: string;
|
|
links: readonly { label: string; href: string }[];
|
|
};
|
|
|
|
export type MegaTabData = {
|
|
id: string;
|
|
nameFa: string;
|
|
nameEn: string;
|
|
href: string;
|
|
image: string;
|
|
/** Second-level categories as columns, each with third-level children */
|
|
columns?: readonly MegaColumn[];
|
|
/** Flat fallback when columns are not provided */
|
|
links?: readonly { label: string; href: string }[];
|
|
};
|
|
|
|
type ProductsMegaMenuProps = {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
tabs?: MegaTabData[];
|
|
};
|
|
|
|
function columnsForTab(tab: MegaTabData): MegaColumn[] {
|
|
if (tab.columns?.length) return [...tab.columns];
|
|
if (tab.links?.length) {
|
|
return [
|
|
{
|
|
title: tab.nameFa,
|
|
href: tab.href,
|
|
links: tab.links,
|
|
},
|
|
];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
export default function ProductsMegaMenu({
|
|
open,
|
|
onClose,
|
|
tabs,
|
|
}: ProductsMegaMenuProps) {
|
|
const list = (tabs?.length ? tabs : MEGA_MENU_TABS) as MegaTabData[];
|
|
const [activeId, setActiveId] = useState(list[0]?.id ?? "coat");
|
|
const active = list.find((t) => t.id === activeId) ?? list[0];
|
|
|
|
if (!open || !active) return null;
|
|
|
|
const columns = columnsForTab(active);
|
|
|
|
return (
|
|
<div
|
|
id="products-mega-menu"
|
|
role="region"
|
|
aria-label="منوی محصولات"
|
|
className="pointer-events-auto absolute inset-x-0 top-full z-40 border-t border-ink/5 bg-white shadow-[0_16px_40px_rgba(0,0,0,0.1)]"
|
|
onMouseLeave={onClose}
|
|
>
|
|
<div className="mx-auto max-w-[1709px] px-4 py-5 sm:px-6 lg:px-10 lg:py-6">
|
|
<div
|
|
role="tablist"
|
|
aria-label="دستهبندی محصولات"
|
|
className="flex flex-wrap items-end justify-start gap-x-1 gap-y-1 border-b border-ink/10"
|
|
>
|
|
{list.map((tab) => {
|
|
const selected = tab.id === active.id;
|
|
return (
|
|
<button
|
|
key={tab.id}
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={selected}
|
|
id={`mega-tab-${tab.id}`}
|
|
aria-controls={`mega-panel-${tab.id}`}
|
|
onMouseEnter={() => setActiveId(tab.id)}
|
|
onFocus={() => setActiveId(tab.id)}
|
|
onClick={() => setActiveId(tab.id)}
|
|
className={`-mb-px border-b-2 px-3 py-2.5 text-center transition-colors sm:px-4 ${
|
|
selected
|
|
? "border-ink"
|
|
: "border-transparent hover:opacity-90"
|
|
}`}
|
|
>
|
|
<span
|
|
className={`block font-doran text-sm font-medium sm:text-[15px] ${
|
|
selected ? "text-ink" : "text-ink/80"
|
|
}`}
|
|
>
|
|
{tab.nameFa}
|
|
</span>
|
|
<span
|
|
dir="ltr"
|
|
className={`mt-0.5 block font-montserrat text-[9px] font-light uppercase tracking-[0.22em] sm:text-[10px] ${
|
|
selected ? "text-ink/70" : "text-ink/40"
|
|
}`}
|
|
>
|
|
{tab.nameEn}
|
|
</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div
|
|
role="tabpanel"
|
|
id={`mega-panel-${active.id}`}
|
|
aria-labelledby={`mega-tab-${active.id}`}
|
|
className="mt-5 flex items-start justify-start gap-6 sm:gap-8 lg:gap-10"
|
|
>
|
|
<div className="min-w-0 flex-1 pt-1">
|
|
<div className="grid grid-cols-2 gap-x-6 gap-y-7 sm:grid-cols-3 sm:gap-x-8 lg:grid-cols-4 xl:grid-cols-5 xl:gap-x-10">
|
|
{columns.map((col) => (
|
|
<div key={col.href + col.title} className="min-w-0">
|
|
<Link
|
|
href={col.href}
|
|
onClick={onClose}
|
|
className="block text-sm font-medium text-ink transition-opacity hover:opacity-70 sm:text-[15px]"
|
|
>
|
|
{col.title}
|
|
</Link>
|
|
{col.links.length > 0 ? (
|
|
<ul className="mt-2.5 flex flex-col gap-1.5 text-[13px] font-light text-ink/70 sm:text-sm">
|
|
{col.links.map((link) => (
|
|
<li key={link.href + link.label}>
|
|
<Link
|
|
href={link.href}
|
|
onClick={onClose}
|
|
className="transition-colors hover:text-ink"
|
|
>
|
|
{link.label}
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : null}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative hidden h-[160px] w-[120px] shrink-0 overflow-hidden bg-[#f3f3f3] sm:block sm:h-[200px] sm:w-[150px] lg:h-[220px] lg:w-[160px]">
|
|
{list.map((tab) => (
|
|
<div
|
|
key={tab.id}
|
|
className={`absolute inset-0 transition-opacity duration-[400ms] ease-out ${
|
|
tab.id === active.id ? "opacity-100" : "opacity-0"
|
|
}`}
|
|
aria-hidden={tab.id !== active.id}
|
|
>
|
|
<Image
|
|
src={tab.image}
|
|
alt=""
|
|
fill
|
|
sizes="160px"
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|