e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import type { Node, Root } from "fumadocs-core/page-tree";
|
|
import type { ReactNode } from "react";
|
|
|
|
export type DocsNeighbour = {
|
|
name: ReactNode;
|
|
url: string;
|
|
section?: ReactNode;
|
|
};
|
|
|
|
type Section = { id: string; name: ReactNode } | undefined;
|
|
type FlatPage = { name: ReactNode; url: string; section: Section };
|
|
|
|
/* fumadocs findNeighbour stops at root:true folder boundaries, so the last page of a section has no next. Flatten every section into one ordered list so navigation continues across sections, tagging each page with the section it belongs to. */
|
|
function flatten(tree: Root): FlatPage[] {
|
|
const pages: FlatPage[] = [];
|
|
let rootCount = 0;
|
|
const walk = (nodes: Node[], section: Section) => {
|
|
for (const node of nodes) {
|
|
if (node.type === "page") {
|
|
pages.push({ name: node.name, url: node.url, section });
|
|
} else if (node.type === "folder") {
|
|
const childSection: Section = node.root
|
|
? { id: `root-${rootCount++}`, name: node.name }
|
|
: section;
|
|
if (node.index) {
|
|
pages.push({
|
|
name: node.index.name,
|
|
url: node.index.url,
|
|
section: childSection,
|
|
});
|
|
}
|
|
walk(node.children, childSection);
|
|
}
|
|
}
|
|
};
|
|
walk(tree.children, undefined);
|
|
return pages;
|
|
}
|
|
|
|
export function getDocsNeighbours(
|
|
tree: Root,
|
|
url: string,
|
|
): { previous?: DocsNeighbour | undefined; next?: DocsNeighbour | undefined } {
|
|
const pages = flatten(tree);
|
|
const index = pages.findIndex((page) => page.url === url);
|
|
if (index === -1) return {};
|
|
const current = pages[index]!;
|
|
|
|
const toNeighbour = (
|
|
page: FlatPage | undefined,
|
|
): DocsNeighbour | undefined => {
|
|
if (!page) return undefined;
|
|
const crossesSection =
|
|
page.section != null && page.section.id !== current.section?.id;
|
|
return {
|
|
name: page.name,
|
|
url: page.url,
|
|
...(crossesSection ? { section: page.section!.name } : {}),
|
|
};
|
|
};
|
|
|
|
return {
|
|
previous: toNeighbour(pages[index - 1]),
|
|
next: toNeighbour(pages[index + 1]),
|
|
};
|
|
}
|