122 lines
3.8 KiB
TypeScript
122 lines
3.8 KiB
TypeScript
import React, {
|
|
AnchorHTMLAttributes,
|
|
ComponentProps,
|
|
DetailedHTMLProps,
|
|
} from "react";
|
|
import { DocsLinkType } from ".";
|
|
import Stack from "../../layout/Stack";
|
|
import { twMerge } from "tailwind-merge";
|
|
import Row from "../../layout/Row";
|
|
import Divider from "../../layout/Divider";
|
|
import { ChevronDown } from "lucide-react";
|
|
import Button from "../../layout/Button";
|
|
|
|
type Props = DetailedHTMLProps<
|
|
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
HTMLAnchorElement
|
|
> & {
|
|
docLink: DocsLinkType;
|
|
wrapperProps?: ComponentProps<typeof Stack>;
|
|
strict?: boolean;
|
|
childWrapperProps?: ComponentProps<typeof Stack>;
|
|
autoExpandAll?: boolean;
|
|
};
|
|
|
|
/**
|
|
* # TWUI Docs Left Aside Link
|
|
* @note use dataset attribute `data-strict` for strict matching
|
|
*
|
|
* @className `twui-docs-left-aside-link`
|
|
*/
|
|
export default function TWUIDocsLink({
|
|
docLink,
|
|
wrapperProps,
|
|
childWrapperProps,
|
|
strict,
|
|
autoExpandAll,
|
|
...props
|
|
}: Props) {
|
|
const [isActive, setIsActive] = React.useState(false);
|
|
const [expand, setExpand] = React.useState(autoExpandAll || false);
|
|
const linkRef = React.useRef<HTMLAnchorElement>(null);
|
|
|
|
React.useEffect(() => {
|
|
if (typeof window !== "undefined") {
|
|
const basePathMatch = window.location.pathname.includes(
|
|
docLink.href
|
|
);
|
|
|
|
const isStrictMatch = Boolean(
|
|
linkRef.current?.getAttribute("data-strict")
|
|
);
|
|
|
|
if (strict || isStrictMatch) {
|
|
setIsActive(window.location.pathname === docLink.href);
|
|
} else {
|
|
setIsActive(basePathMatch);
|
|
}
|
|
|
|
if (basePathMatch) {
|
|
setExpand(true);
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<Stack
|
|
className={twMerge("gap-2 w-full", wrapperProps?.className)}
|
|
{...wrapperProps}
|
|
>
|
|
<Row className="flex-nowrap grow justify-between w-full">
|
|
<a
|
|
href={docLink.href}
|
|
{...props}
|
|
className={twMerge(
|
|
"twui-docs-left-aside-link whitespace-nowrap",
|
|
"grow",
|
|
isActive ? "active" : "",
|
|
props.className
|
|
)}
|
|
ref={linkRef}
|
|
>
|
|
{docLink.title}
|
|
</a>
|
|
|
|
{docLink.children?.[0] && (
|
|
<Button
|
|
variant="ghost"
|
|
color="gray"
|
|
className={twMerge(
|
|
"p-1 hover:opacity-100",
|
|
expand ? "rotate-180 opacity-30" : "opacity-70"
|
|
)}
|
|
onClick={() => setExpand(!expand)}
|
|
>
|
|
<ChevronDown className="text-slate-500" size={20} />
|
|
</Button>
|
|
)}
|
|
</Row>
|
|
{docLink.children && expand && (
|
|
<Row className="items-stretch gap-4 grow w-full flex-nowrap">
|
|
<Divider vertical className="h-auto" />
|
|
<Stack
|
|
className={twMerge(
|
|
"gap-2 w-full",
|
|
childWrapperProps?.className
|
|
)}
|
|
{...childWrapperProps}
|
|
>
|
|
{docLink.children.map((link, index) => (
|
|
<TWUIDocsLink
|
|
docLink={link}
|
|
key={index}
|
|
className="text-sm"
|
|
/>
|
|
))}
|
|
</Stack>
|
|
</Row>
|
|
)}
|
|
</Stack>
|
|
);
|
|
}
|