new-personal-site/components/lib/elements/HeaderNav.tsx
Benjamin Toby d586c56bd3 Updates
2025-07-20 11:15:18 +01:00

99 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 === "/" && linkAttr == "/") {
linkEl.classList.add("active");
} 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");
}
});
}