From 006cc08b81b8188d72839439a06cf0cd9dc749e7 Mon Sep 17 00:00:00 2001 From: John Doe Date: Sat, 9 Sep 2023 17:36:10 +0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Implemented=20NavigationItem=20comp?= =?UTF-8?q?onent=20=F0=9F=9A=80=20Added=20the=20NavigationItem=20component?= =?UTF-8?q?=20to=20handle=20navigation=20=F0=9F=8E=A8=20Improved=20code=20?= =?UTF-8?q?structure=20and=20readability=20=F0=9F=9B=A0=20Fixed=20minor=20?= =?UTF-8?q?issues=20and=20added=20comments=20=F0=9F=94=97=20Ready=20for=20?= =?UTF-8?q?further=20development!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/Navigation/NavigationItem.tsx | 287 +++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 src/shared/Navigation/NavigationItem.tsx diff --git a/src/shared/Navigation/NavigationItem.tsx b/src/shared/Navigation/NavigationItem.tsx new file mode 100644 index 0000000..da04757 --- /dev/null +++ b/src/shared/Navigation/NavigationItem.tsx @@ -0,0 +1,287 @@ +"use client"; + +import { PathName } from "@/routers/types"; +import { Popover, Transition } from "@headlessui/react"; +import { ChevronDownIcon } from "@heroicons/react/24/solid"; +import Image from "next/image"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import React, { FC, Fragment, useEffect, useState } from "react"; + +// <--- NavItemType ---> +export interface MegamenuItem { + id: string; + image: string; + title: string; + items: NavItemType[]; +} +export interface NavItemType { + id: string; + name: string; + isNew?: boolean; + href: PathName; + targetBlank?: boolean; + children?: NavItemType[]; + megaMenu?: MegamenuItem[]; + type?: "dropdown" | "megaMenu" | "none"; +} + +export interface NavigationItemProps { + menuItem: NavItemType; +} + +type NavigationItemWithRouterProps = NavigationItemProps; + +const NavigationItem: FC = ({ menuItem }) => { + const [menuCurrentHovers, setMenuCurrentHovers] = useState([]); + + // CLOSE ALL MENU OPENING WHEN CHANGE HISTORY + const locationPathName = usePathname(); + useEffect(() => { + setMenuCurrentHovers([]); + }, [locationPathName]); + + const onMouseEnterMenu = (id: string) => { + setMenuCurrentHovers((state) => [...state, id]); + }; + + const onMouseLeaveMenu = (id: string) => { + setMenuCurrentHovers((state) => { + return state.filter((item, index) => { + return item !== id && index < state.indexOf(id); + }); + }); + }; + + // ===================== MENU MEGAMENU ===================== + const renderMegaMenu = (menu: NavItemType) => { + const isHover = menuCurrentHovers.includes(menu.id); + + const isFull = menu.megaMenu && menu.megaMenu?.length > 3; + const classPopover = isFull + ? "menu-megamenu--large" + : "menu-megamenu--small relative"; + const classPanel = isFull ? "left-0" : "-translate-x-1/2 left-1/2"; + + return ( + onMouseEnterMenu(menu.id)} + onMouseLeave={() => onMouseLeaveMenu(menu.id)} + > + {() => ( + <> +
{renderMainItem(menu)}
+ + +
+
+ {menu.megaMenu?.map((item) => ( +
+
+
+ +
+
+

+ {item.title} +

+
    + {item.items.map(renderMegaMenuNavlink)} +
+
+ ))} +
+
+
+
+ + )} +
+ ); + }; + + const renderMegaMenuNavlink = (item: NavItemType) => { + return ( +
  • + + {item.name} + +
  • + ); + }; + + // ===================== MENU DROPDOW ===================== + const renderDropdownMenu = (menuDropdown: NavItemType) => { + const isHover = menuCurrentHovers.includes(menuDropdown.id); + return ( + onMouseEnterMenu(menuDropdown.id)} + onMouseLeave={() => onMouseLeaveMenu(menuDropdown.id)} + > + {() => ( + <> +
    {renderMainItem(menuDropdown)}
    + + +
      + {menuDropdown.children?.map((i) => { + if (i.type) { + return renderDropdownMenuNavlinkHasChild(i); + } else { + return ( +
    • + {renderDropdownMenuNavlink(i)} +
    • + ); + } + })} +
    +
    +
    + + )} +
    + ); + }; + + const renderDropdownMenuNavlinkHasChild = (item: NavItemType) => { + const isHover = menuCurrentHovers.includes(item.id); + return ( + onMouseEnterMenu(item.id)} + onMouseLeave={() => onMouseLeaveMenu(item.id)} + > + {() => ( + <> +
    {renderDropdownMenuNavlink(item)}
    + + +
      + {item.children?.map((i) => { + if (i.type) { + return renderDropdownMenuNavlinkHasChild(i); + } else { + return ( +
    • + {renderDropdownMenuNavlink(i)} +
    • + ); + } + })} +
    +
    +
    + + )} +
    + ); + }; + + const renderDropdownMenuNavlink = (item: NavItemType) => { + return ( + + {item.name} + {item.type && ( +