diff --git a/components/api-reference/ApiReferenceLayout.tsx b/components/api-reference/ApiReferenceLayout.tsx index 770cff5ce..2b5740cd5 100644 --- a/components/api-reference/ApiReferenceLayout.tsx +++ b/components/api-reference/ApiReferenceLayout.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { useRouter } from "next/router"; import Meta from "@/components/Meta"; import { Page as TelegraphPage } from "@/components/ui/Page"; @@ -12,6 +12,12 @@ interface Breadcrumb { href: string; } +type PageNeighbor = { + title: string; + path: string; + slug: string; +}; + interface ApiReferenceLayoutProps { children: React.ReactNode; sidebarData: SidebarData; @@ -52,6 +58,56 @@ function convertToLegacySidebarFormat( return [...preSidebarContent, ...resourceSections]; } +/** + * Get the previous and next sections based on the current path. + * Sections are the top-level items in the sidebar (overview + resources). + */ +function getSectionNavigation( + currentPath: string | undefined, + sidebarContent: LegacySidebarSection[], +): { + prevSection: PageNeighbor | undefined; + nextSection: PageNeighbor | undefined; +} { + if (!currentPath) { + return { prevSection: undefined, nextSection: undefined }; + } + + // Find which section the current path belongs to + const currentSectionIndex = sidebarContent.findIndex((section) => { + return currentPath.startsWith(section.slug); + }); + + if (currentSectionIndex === -1) { + return { prevSection: undefined, nextSection: undefined }; + } + + let prevSection: PageNeighbor | undefined = undefined; + let nextSection: PageNeighbor | undefined = undefined; + + // Get previous section + if (currentSectionIndex > 0) { + const prev = sidebarContent[currentSectionIndex - 1]; + prevSection = { + title: prev.title || "", + path: prev.slug, + slug: prev.slug, + }; + } + + // Get next section + if (currentSectionIndex < sidebarContent.length - 1) { + const next = sidebarContent[currentSectionIndex + 1]; + nextSection = { + title: next.title || "", + path: next.slug, + slug: next.slug, + }; + } + + return { prevSection, nextSection }; +} + export function ApiReferenceLayout({ children, sidebarData, @@ -81,6 +137,12 @@ export function ApiReferenceLayout({ preSidebarContent, ); + // Get section navigation (prev/next sections) + const { prevSection, nextSection } = useMemo( + () => getSectionNavigation(currentPath, sidebarContent), + [currentPath, sidebarContent], + ); + // For per-resource pages, currentPath is the resource base path (e.g., /api-reference/users) // This enables same-page routing for links within the current resource const sidebarContextValue = { @@ -131,6 +193,10 @@ export function ApiReferenceLayout({ } /> {children} + diff --git a/layouts/CliReferenceLayout.tsx b/layouts/CliReferenceLayout.tsx index ed95133e0..ae9aee21e 100644 --- a/layouts/CliReferenceLayout.tsx +++ b/layouts/CliReferenceLayout.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { Page } from "@/components/ui/Page"; import { slugToPaths } from "../lib/content"; import Meta from "../components/Meta"; @@ -7,6 +7,63 @@ import { useInitialScrollState } from "../components/ui/Page/helpers"; import { CLI_SIDEBAR } from "../data/sidebars/cliSidebar"; import { ContentActions } from "../components/ui/ContentActions"; import { useScrollToTop } from "../hooks/useScrollToTop"; +import { SidebarContent } from "../data/types"; + +type PageNeighbor = { + title: string; + path: string; + slug: string; +}; + +/** + * Get the previous and next sections based on the current path. + * Sections are the top-level items in the CLI sidebar. + */ +function getSectionNavigation( + currentPath: string | undefined, + sidebarContent: SidebarContent[], +): { + prevSection: PageNeighbor | undefined; + nextSection: PageNeighbor | undefined; +} { + if (!currentPath) { + return { prevSection: undefined, nextSection: undefined }; + } + + // Find which section the current path belongs to + const currentSectionIndex = sidebarContent.findIndex((section) => { + return currentPath.startsWith(section.slug); + }); + + if (currentSectionIndex === -1) { + return { prevSection: undefined, nextSection: undefined }; + } + + let prevSection: PageNeighbor | undefined = undefined; + let nextSection: PageNeighbor | undefined = undefined; + + // Get previous section + if (currentSectionIndex > 0) { + const prev = sidebarContent[currentSectionIndex - 1]; + prevSection = { + title: prev.title, + path: prev.slug, + slug: prev.slug, + }; + } + + // Get next section + if (currentSectionIndex < sidebarContent.length - 1) { + const next = sidebarContent[currentSectionIndex + 1]; + nextSection = { + title: next.title, + path: next.slug, + slug: next.slug, + }; + } + + return { prevSection, nextSection }; +} interface CliReferenceLayoutProps { frontMatter: { @@ -37,6 +94,15 @@ export const CliReferenceLayout = ({ const resource = router.query.resource as string; const mdPath = resource ? `/cli/${resource}.md` : undefined; + // Build the current section path for navigation + const currentSectionPath = resource ? `/cli/${resource}` : "/cli/overview"; + + // Get section navigation (prev/next sections) + const { prevSection, nextSection } = useMemo( + () => getSectionNavigation(currentSectionPath, CLI_SIDEBAR), + [currentSectionPath], + ); + return ( {children} + diff --git a/pages/api-reference/index.tsx b/pages/api-reference/index.tsx index 2a0961597..d91f3f973 100644 --- a/pages/api-reference/index.tsx +++ b/pages/api-reference/index.tsx @@ -27,6 +27,7 @@ function ApiReferenceOverview({ preSidebarContent={API_REFERENCE_OVERVIEW_CONTENT} title="API reference" description="Complete reference documentation for the Knock API." + currentPath="/api-reference/overview" > diff --git a/pages/mapi-reference/index.tsx b/pages/mapi-reference/index.tsx index ae7925df4..5b3ce4866 100644 --- a/pages/mapi-reference/index.tsx +++ b/pages/mapi-reference/index.tsx @@ -27,6 +27,7 @@ function MapiReferenceOverview({ preSidebarContent={MAPI_REFERENCE_OVERVIEW_CONTENT} title="Management API reference" description="Complete reference documentation for the Knock Management API." + currentPath="/mapi-reference/overview" >