import { FC, useCallback, useMemo, ReactNode } from "react";
import {
Box,
Collapse,
Flex,
forwardRef,
HStack,
Icon,
Link,
Menu,
MenuButton,
MenuItem,
MenuList,
Text,
Stack,
useColorModeValue,
useDisclosure,
Container,
useBreakpointValue,
} from "@chakra-ui/react";
import { intl } from "locale";
import {
FiHome,
FiSettings,
FiUser,
FiBook,
FiLock,
FiShield,
FiMonitor,
FiChevronDown,
} from "react-icons/fi";
import { Link as RouterLink, useLocation } from "react-router-dom";
interface NavItem {
/** Displayed label */
label: string;
/** Icon shown before the label */
icon: ReactNode;
/** Link where to navigate to */
to?: string;
subItems?: { label: string; to: string }[];
}
const navItems: NavItem[] = [
{
label: intl.formatMessage({ id: "dashboard.title" }),
icon: ,
to: "/",
},
{
label: intl.formatMessage({ id: "hosts.title" }),
icon: ,
subItems: [
{
label: intl.formatMessage({ id: "hosts.title" }),
to: "/hosts",
},
{
label: intl.formatMessage({ id: "upstreams.title" }),
to: "/upstreams",
},
],
},
{
label: intl.formatMessage({ id: "access-lists.title" }),
icon: ,
to: "/access-lists",
},
{
label: intl.formatMessage({ id: "ssl.title" }),
icon: ,
subItems: [
{
label: intl.formatMessage({ id: "certificates.title" }),
to: "/ssl/certificates",
},
{
label: intl.formatMessage({ id: "certificate-authorities.title" }),
to: "/ssl/authorities",
},
{
label: intl.formatMessage({ id: "dns-providers.title" }),
to: "/ssl/dns-providers",
},
],
},
{
label: intl.formatMessage({ id: "audit-log.title" }),
icon: ,
to: "/audit-log",
},
{
label: intl.formatMessage({ id: "users.title" }),
icon: ,
to: "/users",
},
{
label: intl.formatMessage({ id: "settings.title" }),
icon: ,
subItems: [
{
label: intl.formatMessage({ id: "general-settings.title" }),
to: "/settings/general",
},
{
label: intl.formatMessage({ id: "nginx-templates.title" }),
to: "/settings/nginx-templates",
},
],
},
];
interface NavigationMenuProps {
/** Navigation is currently hidden on mobile */
mobileNavIsOpen: boolean;
closeMobileNav: () => void;
}
function NavigationMenu({
mobileNavIsOpen,
closeMobileNav,
}: NavigationMenuProps) {
const isMobile = useBreakpointValue({ base: true, md: false });
return (
<>
{isMobile ? (
) : (
)}
>
);
}
/** Single tab element for desktop navigation */
type NavTabProps = Omit & { active?: boolean };
const NavTab = forwardRef(
({ label, icon, to, active, ...props }, ref) => {
const linkColor = useColorModeValue("gray.500", "gray.200");
const linkHoverColor = useColorModeValue("gray.900", "white");
return (
{icon}
{label}
);
},
);
const DesktopNavigation: FC = () => {
const path = useLocation().pathname;
const activeNavItemIndex = useMemo(
() =>
navItems.findIndex((item) => {
// Find the nav item whose location / sub items location is the beginning of the currently active path
if (item.to) {
if (item.to === "/") {
return path === item.to;
}
return path.startsWith(item.to !== "" ? item.to : "/dashboard");
} else if (item.subItems) {
return item.subItems.some((subItem) => path.startsWith(subItem.to));
}
return false;
}),
[path],
);
return (
{navItems.map((navItem, index) => {
const { subItems, ...propsWithoutSubItems } = navItem;
const additionalProps: Partial = {};
if (index === activeNavItemIndex) {
additionalProps["active"] = true;
}
if (subItems) {
return (
);
} else {
return (
);
}
})}
);
};
const MobileNavigation: FC> = ({
closeMobileNav,
}) => {
return (
{navItems.map((navItem, index) => (
))}
);
};
const MobileNavItem: FC<
NavItem & {
index: number;
closeMobileNav: NavigationMenuProps["closeMobileNav"];
}
> = ({ closeMobileNav, ...props }) => {
const { isOpen, onToggle } = useDisclosure();
const onClickHandler = useCallback(() => {
if (props.subItems) {
// Toggle accordeon
onToggle();
} else {
// Close menu on navigate
closeMobileNav();
}
}, [closeMobileNav, onToggle, props.subItems]);
return (
{props.icon}
{props.label}
{props.subItems && (
)}
{props.subItems &&
props.subItems.map((subItem, subIndex) => (
{subItem.label}
))}
);
};
export { NavigationMenu };