Skip to main content
ESC

App Organization

Robindoc can be considered to consist of several parts:

Organizing Documentation Files 

One of the main advantages of Robindoc is that documentation files can reside in any source — whether they are files outside the current directory or a remote git repository (more about sources on the "Data Source" page).

Robindoc’s main approach is that you don’t adjust the location of markdown files for Robindoc; instead, Robindoc builds the site from your markdown files. In other words, you place files so that they can be read in GitHub, and Robindoc serves as a convenient interface.

However, when using the automatic mode for generating the structure, the documentation file structure should match the desired structure on the site. In manual mode, you can organize the documentation files as you wish, but it is still recommended to reflect the site’s structure.

Application Setup and Configuration 

You can initialize Robindoc on any subpath of your site, as long as you specify the basePath in the project initialization and pass the correct path in the Robindoc components.

After initialization, you will receive Sidebar, Page, getPages, getMeta, and getPageContent. Read more on the Initialization page.

Global elements - RobinProvider, Header, Footer, Main and Sidebar - should ideally be placed above all pages and reused across all. Currently, Robindoc works only with the App Router. Once RSC is available for the Pages Router, Robindoc will automatically support it as well.

Page Setup 

Next.js supports dynamic routes, so it is recommended to set up one dynamic segment  for all documentation pages.

app/docs/[[...path]]/page.tsx
import { Page, Sidebar, getMeta, getPages } from "../robindoc";

export const Page: React.FC<{ params: { path?: string[] } }> = ({ params }) => {
const pathname = "/docs/" + (params.path?.join("/") || "");

return <Page pathname={pathname} />;
};

For more details about the props, refer to the Page element page.

You should also set up metadata generation and static parameters generation (if you want to use SSG, which is highly recommended):

app/docs/[[...path]]/page.tsx
import { Page, Sidebar, getMeta, getPages } from "../robindoc";

// ...

export const generateMetadata = async ({
params,
}: {
params: { path?: string[] };
}) => {
const pathname = "/docs/" + (params.path?.join("/") || "");
const meta = await getMeta(pathname);

return meta;
};

export const generateStaticParams = async () => {
const pages = await getPages("/docs/");
return pages.map((page) => ({ path: page.split("/").slice(2) }));
};

Robindoc Setup 

It is recommended to place the Robindoc initialization near this route.

app/docs/robindoc.ts
import { initializeRobindoc } from "robindoc";

export const { Page, Sidebar, getPages, getMeta, getPageContent } =
initializeRobindoc({
configuration: {
sourceRoot: "../docs",
basePath: "/docs",
gitToken: "YOUR_TOKEN",
fetcher: (url, init) =>
fetch(url, { ...init, cache: "force-cache", next: { tags: ["docs"] } }),
},
items: "auto",
});
When uploading to Vercel, the final image will contain only files inside the next.js project

Layout Setup 

The Next.js Layout should be placed one level up so that it remains static for all pages.

app/docs/layout.tsx
import { RobinProvider, Header, Footer, Main } from "robindoc";
import { Sidebar } from "./robindoc";
import Logo from "./logo";

import "robindoc/lib/styles.css";

export const Layout = ({ children }) => {
return (
<RobinProvider>
<Header logo={<Logo />} />
<Main>
<Sidebar />
{children}
</Main>
<Footer copyright="© 2024 All rights reserved" />
</RobinProvider>
);
};

For more details on configuring elements, refer to the RobinProvider, Header, Sidebar, Footer, and Main block pages.

Search Setup 

If you want to enable search, you can create your own API route and pass the path to it in your Header.

app/api/search/route.ts
export const GET = async (request: Request) => {
const url = new URL(request.url);
const search = url.searchParams.get("s");

const headers = new Headers();
headers.set("Content-Type", "application/json; charset=UTF-8");

if (!search) return new Response(JSON.stringify([]), { headers });

const searchResults = await advancedSearcher(search);

return new Response(JSON.stringify(searchResults), { headers });
};
TypeScript
JavaScript
app/docs/layout.tsx
export const Layout = ({ children }) => {
return (
<RobinProvider>
<Header logo={<Logo />} searcher="/api/search" />
{/* ... */}
</RobinProvider>
);
};
app/docs/layout.js
export const Layout = ({ children }) => {
return (
<RobinProvider>
<Header logo={<Logo />} searcher="/api/search" />
{/* ... */}
</RobinProvider>
);
};

Vercel 

Since the image in Vercel does not include indirect files - for working with documentation on the server - local documentation files need to be passed explicitly via outputFileTracingIncludes config.

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
outputFileTracingIncludes: {
"/api/search": ["./docs/**/*", "./blog/**/*", "./README.md"],
},
},
};

For more details on search configuration, refer to the Search page.

Sitemap Setup 

To generate a sitemap in next.js, you can use a special sitemap file  in combination with getPages tool:

./app/sitemap.ts
import { type MetadataRoute } from "next";
import { getPages } from "./docs/robindoc";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const pages = await getPages();

return pages.map((page) => ({
url: `https://robindoc.com${page}`,
lastModified: new Date(),
changeFrequency: "daily",
priority: 0.7,
}));
}
Previous
Initialization
Next
Structure
Return to navigation