diff --git a/src/components/docs-breadcrumbs.jsx b/src/components/docs-breadcrumbs.jsx
new file mode 100644
index 00000000..7ab8ccbb
--- /dev/null
+++ b/src/components/docs-breadcrumbs.jsx
@@ -0,0 +1,69 @@
+import { ChevronRightIcon } from "@heroicons/react/24/outline";
+import { useRouter } from "next/router";
+import Link from "@/components/link";
+import { normalizeHref } from "@/utils/strings";
+
+export default function DocsBreadcrumbs({ routes }) {
+ const generateBreadcrumbs = (breadcrumbRoutes, currentRoute) => {
+ const breadcrumbs = [];
+
+ const traverse = (navigationRoutes, path) => {
+ const currentIndex = navigationRoutes.findIndex(
+ (route) => normalizeHref(route.route) === normalizeHref(path),
+ );
+
+ if (currentIndex === -1) {
+ return;
+ }
+
+ breadcrumbs.unshift(navigationRoutes[currentIndex]);
+
+ const parentPath = navigationRoutes[currentIndex].parentPath;
+ if (!parentPath) {
+ return;
+ }
+
+ traverse(navigationRoutes, parentPath);
+ };
+
+ traverse(routes, currentRoute);
+ return breadcrumbs;
+ };
+
+ const router = useRouter();
+ const currentPath = router.pathname;
+ const breadcrumbLinks = generateBreadcrumbs(routes, currentPath);
+
+ if (breadcrumbLinks.length === 0 || currentPath === "/docs") {
+ return;
+ }
+
+ const homeRoute = routes[0];
+ homeRoute.title = "Docs";
+ breadcrumbLinks.unshift(homeRoute);
+
+ return (
+
+
+ {breadcrumbLinks.map((breadcrumb, index) =>
+ normalizeHref(breadcrumb.route) === normalizeHref(currentPath) ? (
+ {breadcrumb.title}
+ ) : (
+
+ {breadcrumb.title}
+
+
+
+
+ ),
+ )}
+
+
+ );
+}
diff --git a/src/components/docs-layout.jsx b/src/components/docs-layout.jsx
index 9ea471a3..37f9006b 100644
--- a/src/components/docs-layout.jsx
+++ b/src/components/docs-layout.jsx
@@ -4,17 +4,38 @@ import {
DisclosurePanel,
} from "@headlessui/react";
import { ChevronRightIcon, ChevronDownIcon } from "@heroicons/react/24/outline";
+import DocsBreadcrumbs from "./docs-breadcrumbs";
+import DocsPreviousNextLinks from "./docs-previous-next-link";
import OnThisPageNav from "./on-this-page-nav";
import DocsNav from "@/components/docs-nav";
import routes from "@/pages/docs/nav.json";
import "rehype-callouts/theme/vitepress";
+const flattenRoutes = (routeConfig) => {
+ const flatRoutes = [];
+
+ const traverse = (innerRoutes, parentPath = "") => {
+ for (const route of innerRoutes) {
+ const fullPath = `${parentPath}${route.route}`;
+ flatRoutes.push({ ...route, fullPath, parentPath });
+
+ if (route.children) {
+ traverse(route.children, `${parentPath}${route.route}`);
+ }
+ }
+ };
+
+ traverse(routeConfig);
+ return flatRoutes;
+};
+
export default function DocumentPage({ children, metadata }) {
+ const flatRoutes = flattenRoutes(routes);
return (
<>
@@ -22,21 +43,26 @@ export default function DocumentPage({ children, metadata }) {
Menu
-
+
-
+
-
+
+
{metadata?.title && (
- {metadata.title}
+ {metadata.title}
)}
{children}
+
>
diff --git a/src/components/docs-nav.jsx b/src/components/docs-nav.jsx
index a36d0ae2..e8b6189e 100644
--- a/src/components/docs-nav.jsx
+++ b/src/components/docs-nav.jsx
@@ -1,6 +1,6 @@
import { Fragment } from "react";
import Link from "@/components/link";
-import { classNames } from "@/utils/strings";
+import { normalizeHref, classNames } from "@/utils/strings";
export default function DocsNav({ as, routes, level = 0, className }) {
const As = as || Fragment;
@@ -29,7 +29,7 @@ function NavItem({ item, level, ...props }) {
normalizeHref(route.route) === normalizeHref(currentPath),
+ );
+
+ if (currentIndex === -1) {
+ return;
+ }
+
+ const previousPage = routes[currentIndex - 1];
+ const nextPage = routes[currentIndex + 1];
+
+ return (
+
+ );
+}
diff --git a/src/components/footer.jsx b/src/components/footer.jsx
index d08daedb..68a9d100 100644
--- a/src/components/footer.jsx
+++ b/src/components/footer.jsx
@@ -7,7 +7,7 @@ export default function Footer() {
-
+
Powered by{" "}
+
-
+
-
+
{socialIcons.map(({ url, name, icon: Icon }) => (
{
);
});
-export default function PrimaryMenu({ className }) {
+export default function PrimaryMenu({ isMenuOpen, setIsMenuOpen, className }) {
return (