Skip to content

Instantly share code, notes, and snippets.

@crisgon
Created July 6, 2020 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crisgon/c7a6a13c0d4d5f36e6b8867d634f0737 to your computer and use it in GitHub Desktop.
Save crisgon/c7a6a13c0d4d5f36e6b8867d634f0737 to your computer and use it in GitHub Desktop.
import React, { useState, useEffect, useMemo } from "react";
import { Link, useLocation } from "react-router-dom";
import cn from "classnames";
import { Icon } from "antd";
import { ArrowNav } from "../../NavSVGS";
import s from "./style.scss";
interface Props {
id: string;
label: string;
icon: string | React.ReactNode | null;
link: string | null;
isRoot: boolean | null;
data: IMenuItems;
}
interface IMenuItems {
id: string;
label: string;
icon?: string | React.ReactNode;
link?: string;
isRoot?: boolean;
nodes: IMenuItems[];
}
function NavItem({ data, id, label, link, icon, isRoot }: Props) {
const [open, setOpen] = useState<boolean>(false);
const { pathname } = useLocation();
useEffect(() => {
setOpen(() => {
if (isRoot && pathname.includes(id)) return true;
return (
data.nodes.some(item => item.link === pathname) || link === pathname
);
});
}, []);
const isActive = useMemo(() => {
return link === pathname;
}, [link, pathname]);
function generateIcon(icon: any) {
if (typeof icon === "string") {
return <Icon type={icon} />;
}
return <Icon component={icon} />;
}
return (
<li
className={cn(s.listItem, {
[s.listItemActive as string]: open && isRoot && data.nodes.length,
})}
>
<div
className={cn(s.listItemLabelContainer, {
[s.listItemLabelContainer_root as string]: isRoot,
[s.listItemLabelContainer_root_active as string]:
(isRoot && open && data.nodes.length) ||
(isRoot && isActive && !data.nodes.length),
})}
>
{generateIcon(icon)}
<span onClick={() => setOpen(!open)} className={s.listItemLabel}>
{Boolean(!isRoot && data.nodes.length) && (
<span className={open ? s.arrowNavOpen : s.arrowNavClose}>
<ArrowNav />
</span>
)}
{link ? (
<Link
to={link}
className={cn({
[s.linkActive as string]: isActive && !isRoot,
})}
>
{label}
</Link>
) : (
label
)}
</span>
</div>
{Boolean(open && data.nodes.length) && (
<ul className={s.list}>
{data.nodes.map(d => (
<NavItem
key={d.label}
data={d}
id={d.id}
label={d.label}
link={d.link ?? null}
icon={d.icon ?? null}
isRoot={d.isRoot ?? null}
/>
))}
</ul>
)}
</li>
);
}
export default NavItem;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment