98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import React, { DetailedHTMLProps, HTMLAttributes, ReactNode } from "react";
|
|
import { twMerge } from "tailwind-merge";
|
|
import Row from "../layout/Row";
|
|
import HeaderNavLinkComponent from "./HeaderNavLinkComponent";
|
|
|
|
export type TWUI_HEADER_NAV_PROPS = DetailedHTMLProps<
|
|
HTMLAttributes<HTMLElement>,
|
|
HTMLElement
|
|
> & {
|
|
headerLinks: TwuiHeaderLink[];
|
|
customDropdowns?: {
|
|
url: string;
|
|
content: ReactNode;
|
|
}[];
|
|
};
|
|
|
|
export type TwuiHeaderLink = {
|
|
title: string;
|
|
url: string;
|
|
strict?: boolean;
|
|
dropdown?: ReactNode;
|
|
children?: TwuiHeaderLink[];
|
|
icon?: ReactNode;
|
|
};
|
|
|
|
/**
|
|
* # Header Nav Component
|
|
* @className twui-header-nav
|
|
* @className twui-header-nav-link-component
|
|
* @className twui-header-nav-link-icon
|
|
* @className twui-header-nav-link-dropdown
|
|
*/
|
|
export default function HeaderNav({
|
|
headerLinks,
|
|
customDropdowns,
|
|
...props
|
|
}: TWUI_HEADER_NAV_PROPS) {
|
|
React.useEffect(() => {
|
|
twuiAddActiveLinksFn({ selector: ".twui-header-nav-link-component a" });
|
|
}, []);
|
|
|
|
return (
|
|
<nav
|
|
{...props}
|
|
className={twMerge(
|
|
"twui-header-nav w-full xl:w-auto",
|
|
props.className
|
|
)}
|
|
>
|
|
<Row className="gap-x-2 gap-y-2 flex-col xl:flex-row items-start xl:items-stretch">
|
|
{headerLinks.map((link, index) => {
|
|
const targetCustomDropdown = customDropdowns?.find(
|
|
(d) => d.url == link.url
|
|
);
|
|
return (
|
|
<HeaderNavLinkComponent
|
|
link={link}
|
|
key={index}
|
|
dropdown={targetCustomDropdown?.content}
|
|
/>
|
|
);
|
|
})}
|
|
</Row>
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
type AddActiveLinkParams = {
|
|
selector?: string;
|
|
wrapperEl?: HTMLElement;
|
|
};
|
|
|
|
export function twuiAddActiveLinksFn({
|
|
selector,
|
|
wrapperEl,
|
|
}: AddActiveLinkParams) {
|
|
(wrapperEl || document).querySelectorAll(selector || "a").forEach((ln) => {
|
|
const linkEl = ln as HTMLAnchorElement;
|
|
const isLinkStrict = linkEl.dataset.strict;
|
|
|
|
const linkAttr = linkEl.getAttribute("href");
|
|
|
|
if (window.location.pathname === "/") {
|
|
} else if (
|
|
isLinkStrict &&
|
|
linkEl.getAttribute("href") === window.location.pathname
|
|
) {
|
|
linkEl.classList.add("active");
|
|
} else if (
|
|
linkAttr &&
|
|
window.location.pathname.startsWith(linkAttr) &&
|
|
!isLinkStrict
|
|
) {
|
|
linkEl.classList.add("active");
|
|
}
|
|
});
|
|
}
|