cant decide how to have gap between menu and submenu in nextjs project sidebar

36 Views Asked by At

I am trying to make a sidebar, where a menu might have submenu kind of dropdown, the problem i am facing is when i open the submenu with MdArrowDropDown icon, it perfectly shows up , but it blocks the next menu item or overlaps it .i cant give it spacing . here is my code :

` /* eslint-disable react-hooks/exhaustive-deps */ import { type IconType } from "react-icons"; import { PiUserList, PiChats, PiUserLight, PiBellLight, PiStarLight, PiBriefcaseLight, PiCalendarCheck, PiCurrencyCircleDollarLight, PiIdentificationCardLight, } from "react-icons/pi"; import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect, useMemo, useRef, useState } from "react"; import { type IconProps } from "types/common/types"; import { Flex } from "~/components/atoms/features/layout/Flex"; import { Text } from "~/components/atoms/features/typography/Text"; import { MdArrowDropDown } from "react-icons/md"; import { MdArrowDropUp } from "react-icons/md";

  type Menu1Layer = {
    href: string;
    iconName?: IconProps["iconName"];
    label: string;
    badgeCount?: number | string;
    isOpen: boolean;
    activePathWord: string;
    hidden: boolean;
  };
  type Props = {
    iconName: IconProps["iconName"];
    isMenuOpen: boolean;
    title?: string;
    hasDetail?: boolean;
    isDetailOpen?: boolean;
    isActive?: boolean;
    className?: string;
    dataCy?: string;
    href: string;
    items?: Menu1Layer[];
  };

  export const Item = (props: Props) => {
    const {
      iconName = "Dashboard",
      isMenuOpen,
      title,
      hasDetail = false,
      isDetailOpen = false,
      className,
      dataCy,
      href,
      items,
    } = props;

    const getIconComponent = (iconName: string): IconType => {
      switch (iconName) {
        case "UserList":
          return PiUserList;
        case "Chat":
          return PiChats;
        case "CalendarCheck":
          return PiCalendarCheck;
        case "Star":
          return PiStarLight;
        case "Bell":
          return PiBellLight;
        case "User":
          return PiUserLight;
        case "Briefcase":
          return PiBriefcaseLight;
        case "PiCurrencyCircleDollarLight":
          return PiCurrencyCircleDollarLight;
        case "PiIdentificationCardLight":
          return PiIdentificationCardLight;

        default:
          return PiStarLight;
      }
    };
    const [isOver, setIsOver] = useState<boolean>(false);
    const [menuactive, setMenuActive] = useState<boolean>(false);
    const [openDropDown, setOpenDropDown] = useState<boolean>(false);
    const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);

    const handleDropdownToggle = () => {
      setOpenDropDown((prevOpenDropDown) => !prevOpenDropDown);
      setMenuActive((prevActive) => !prevActive);
      isActive;
    };

    const menuref = useRef<HTMLDivElement>(null);
    useEffect(() => {
      const handler = (event: MouseEvent) => {
        if (menuref.current && !menuref.current.contains(event.target as Node)) {
          setOpenDropDown(false);
          setMenuActive(false);
        }
      };

      document.addEventListener("mousedown", handler);

      return () => {
        document.removeEventListener("mousedown", handler);
      };
    });

    const getColor = () => {
      if (isOver || isActive || menuactive) return "border border-primary";
      return "bg-[#FFFFFF]";
    };

    const router = useRouter();

    const x = items?.find((item) => router.pathname.endsWith(item.href));
    const child: number[] = [];

    items?.map((item, index) => {
      if (router.pathname.endsWith(item.href)) {
        return child.push(index);
      }
    });
    const isActive = href && router.pathname.endsWith(href) && child.length === 0;

    const IconComponent = getIconComponent(iconName);

    const contentItem = useMemo(
      () => (
        <>
          {" "}
          <Flex
            direction="row"
            justifyContent="start"
            className={`${isActive ?? (menuactive && "bg-primary")} w-full px-1`}
            gap={
              !isMenuOpen &&
              (isOver || (!isMenuOpen && isDetailOpen)) &&
              hasDetail
                ? "0px"
                : "8px"
            }
            wrap={false}
          >
            {!hasDetail && (
              <IconComponent
                size={24}
                color={
                  (isOver && !isActive) || !isMenuOpen
                    ? "#FF00FF"
                    : isActive
                    ? "#FFFFFF"
                    : "#000000"
                }
              />
            )}

            {hasDetail && (
              <IconComponent
                size={28}
                color={
                  menuactive || isActive
                    ? "#FFFFFF"
                    : isOver && !menuactive
                    ? "#FF00FF"
                    : "#000000"
                }
              />
            )}
            {!hasDetail && (
              <Link href={href}>
                <Text
                  text={title ?? ""}
                  className={`${isOver && !menuactive && "text-primary"} ${
                    isActive && "text-white"
                  } xl:text  w-full overflow-hidden text-ellipsis font-bold  lg:text-[16px]`}
                />
              </Link>
            )}
            {hasDetail && isMenuOpen && href && (
              <>
                <Link href={href}>
                  <Text
                    text={title ?? ""}
                    className={`${isOver && !menuactive && "text-primary"} ${
                      isActive && "text-white"
                    } xl:text  w-full overflow-hidden text-ellipsis font-bold  lg:text-[16px]`}
                  />
                </Link>
                <div
                  className={`relative ${openDropDown ? "z-10" : "z-0"}`}
                  ref={menuref}
                >
                  {openDropDown && (
                    <MdArrowDropUp
                      size={24}
                      onClick={handleDropdownToggle}
                      className="ml:4"
                    />
                  )}

                  {!openDropDown && (
                    <MdArrowDropDown
                      size={24}
                      onClick={handleDropdownToggle}
                      color={isOver && !menuactive ? "#FF00FF" : undefined}
                      className="ml:4"
                    />
                  )}
                  {openDropDown && (
                    <div className="absolute left-0 top-full w-[180px] flex-col pt-2">
                      {openDropDown &&
                        items?.map((item, i) => {
                          const iconName = item.iconName ?? "DefaultIconName";
                          const IconComponent = getIconComponent(iconName);

                          return (
                            <div
                              key={item.label}
                              className={`${i === child[0] && "bg-primary"} ${
                                isOver &&
                                hoveredIndex === i &&
                                "border border-primary"
                              } mr-10 mt-2 flex h-full w-[175px] px-3  py-3 md:h-fit md:w-[160px] md:gap-0`}
                              onMouseEnter={() => setHoveredIndex(i)}
                              onMouseLeave={() => setHoveredIndex(null)}
                            >
                              <IconComponent
                                size={24}
                                color={
                                  i === child[0]
                                    ? "#FFFFFF"
                                    : hoveredIndex === i &&
                                      isOver &&
                                      i !== child[0] &&
                                      !isActive
                                    ? "#FF00FF"
                                    : "#000000"
                                }
                              />
                              <Link href={item.href}>
                                <Text
                                  text={item.label ?? ""}
                                  className={`${
                                    hoveredIndex === i && isOver
                                      ? "text-primary"
                                      : "text-[#1D212D]"
                                  } ${
                                    i === child[0] && "text-white"
                                  } xl:text my-1 w-full overflow-hidden text-ellipsis pl-2 font-bold lg:text-[16px]`}
                                />
                              </Link>
                            </div>
                          );
                        })}
                    </div>
                  )}
                </div>
              </>
            )}
          </Flex>
        </>
      ),
      [
        isOver,
        isActive,
        isDetailOpen,
        isMenuOpen,
        router,
        openDropDown,
        hoveredIndex,
      ],
    );

    const CLASSNAME = `flex flex-row items-center ${
      isMenuOpen ? "justify-between" : "justify-center lg:w-[30px] xl:w-[52px]"
    } ${menuactive && "bg-primary text-white"} ${
      isActive && "bg-primary"
    }  whitespace-nowrap gap-[4px] px-[10px] py-[6px] w-full ${getColor()} ${className}`;
    return (
      <div
        className={CLASSNAME}
        onMouseOver={() => {
          setIsOver(true);
        }}
        onMouseLeave={() => {
          setIsOver(false);
        }}
        data-cy={dataCy}
      >
        {contentItem}
      </div>
    );
  };

`

0

There are 0 best solutions below