Updates
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
import React, { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { DocsLinkType } from ".";
|
||||
import Stack from "../../layout/Stack";
|
||||
import TWUIDocsLink from "./TWUIDocsLink";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import Span from "../../layout/Span";
|
||||
import Row from "../../layout/Row";
|
||||
import { ArrowUpRight, LinkIcon, ListIcon } from "lucide-react";
|
||||
import Link from "../../layout/Link";
|
||||
|
||||
type Props = DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> & {
|
||||
before?: React.ReactNode;
|
||||
after?: React.ReactNode;
|
||||
autoExpandAll?: boolean;
|
||||
editPageURL?: string;
|
||||
};
|
||||
export default function TWUIDocsRightAside({
|
||||
after,
|
||||
before,
|
||||
autoExpandAll,
|
||||
editPageURL,
|
||||
...props
|
||||
}: Props) {
|
||||
const [links, setLinks] = React.useState<DocsLinkType[]>([]);
|
||||
const [ready, setReady] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!ready) return;
|
||||
|
||||
const headerHrefs = document.querySelectorAll(
|
||||
".twui-docs-header-anchor"
|
||||
);
|
||||
|
||||
const linksArr: DocsLinkType[] = [];
|
||||
|
||||
for (let i = 0; i < headerHrefs.length; i++) {
|
||||
const anchorEl = headerHrefs[i] as HTMLAnchorElement;
|
||||
|
||||
const isH2Element = anchorEl.querySelector("h2") !== null;
|
||||
|
||||
if (isH2Element) {
|
||||
let newLink: DocsLinkType = {
|
||||
title: anchorEl.textContent || "",
|
||||
href: `#${anchorEl.id}`,
|
||||
};
|
||||
|
||||
let nexElIndex = i + 1;
|
||||
|
||||
while (nexElIndex < headerHrefs.length) {
|
||||
const nextElement = headerHrefs[
|
||||
nexElIndex
|
||||
] as HTMLAnchorElement;
|
||||
|
||||
const nextElementH3 = nextElement.querySelector("h3");
|
||||
|
||||
const isNextElementH2 =
|
||||
nextElement.querySelector("h2") !== null;
|
||||
|
||||
if (isNextElementH2) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!nextElementH3) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newLink.children) {
|
||||
newLink.children = [];
|
||||
}
|
||||
|
||||
newLink.children.push({
|
||||
title: nextElementH3.textContent || "",
|
||||
href: `#${nextElement.id}`,
|
||||
});
|
||||
|
||||
nexElIndex++;
|
||||
}
|
||||
|
||||
linksArr.push(newLink);
|
||||
}
|
||||
}
|
||||
|
||||
setLinks(linksArr);
|
||||
}, [ready]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!links.length) return;
|
||||
|
||||
const headerHrefs = document.querySelectorAll(
|
||||
"a.twui-docs-header-anchor"
|
||||
);
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const id = entry.target.id;
|
||||
|
||||
const link = document.querySelector(
|
||||
`.twui-docs-right-aside a[href="#${id}"]`
|
||||
);
|
||||
if (link) {
|
||||
link.classList.add("active");
|
||||
}
|
||||
} else {
|
||||
const id = entry.target.id;
|
||||
const link = document.querySelector(
|
||||
`.twui-docs-right-aside a[href="#${id}"]`
|
||||
);
|
||||
if (link) {
|
||||
link.classList.remove("active");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
headerHrefs.forEach((headerHref) => {
|
||||
observer.observe(headerHref);
|
||||
});
|
||||
}, [links]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setReady(true);
|
||||
}, 100);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<aside
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"pb-10 hidden xl:flex min-w-[150px] max-w-[200px]",
|
||||
"sticky top-6 twui-docs-right-aside",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
<Stack className="w-full overflow-hidden">
|
||||
{before}
|
||||
<Stack className="w-full">
|
||||
<Row>
|
||||
<ListIcon size={12} opacity={0.5} />
|
||||
<Span size="smaller" variant="faded">
|
||||
On this page
|
||||
</Span>
|
||||
</Row>
|
||||
{links.map((link, index) => (
|
||||
<TWUIDocsLink
|
||||
docLink={link}
|
||||
key={index}
|
||||
autoExpandAll
|
||||
childWrapperProps={{
|
||||
className: "pl-2",
|
||||
}}
|
||||
wrapperProps={{
|
||||
className:
|
||||
"[&_svg]:hidden [&_a]:text-xs [&_a]:overflow-hidden [&_a]:overflow-ellipsis",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
{after}
|
||||
{editPageURL && (
|
||||
<Link
|
||||
href={editPageURL}
|
||||
target="_blank"
|
||||
className="text-[12px] mt-2"
|
||||
>
|
||||
<Row className="gap-2">
|
||||
<LinkIcon size={12} opacity={0.5} />
|
||||
<span>Edit This Page</span>
|
||||
<ArrowUpRight size={15} className="-ml-1" />
|
||||
</Row>
|
||||
</Link>
|
||||
)}
|
||||
</Stack>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user