diff --git a/docs/01-getting-started/03-initialization.md b/docs/01-getting-started/03-initialization.md index 3a583d23..fb914a8d 100644 --- a/docs/01-getting-started/03-initialization.md +++ b/docs/01-getting-started/03-initialization.md @@ -4,12 +4,12 @@ To use Robindoc with all its features, you need to initialize it. To do this, yo ## Calling the Method -The method will return dynamic components [`Page`](../03-customization/01-elements/page.md) and [`Sidebar`](../03-customization/01-elements/sidebar.md), as well as the methods [`getPages`](../03-customization/02-tools/get-pages.md), [`getMeta`](../03-customization/02-tools/get-meta.md), and [`getPageContent`](../03-customization/02-tools/get-page-content.md). +The method will return dynamic components [`Page`](../03-customization/01-elements/page.md) and [`Sidebar`](../03-customization/01-elements/sidebar.md), as well as the methods [`getStaticParams`](../03-customization/02-tools/get-static-params.md), [`getMetadata`](../03-customization/02-tools/get-metadata.md), and [`getPageData`](../03-customization/02-tools/get-page-data.md). ```tsx filename="app/docs/robindoc.ts" tab="TypeScript" switcher clone="jsx|JavaScript|app/docs/robindoc.js" import { initializeRobindoc } from "robindoc"; -export const { Page, Sidebar, getPages, getMeta, getPageContent } = +export const { Page, Sidebar, getStaticParams, getMetadata, getPageData } = initializeRobindoc({ configuration: { sourceRoot: "../docs", diff --git a/docs/01-getting-started/04-app-organization.md b/docs/01-getting-started/04-app-organization.md index f10899d9..03c97581 100644 --- a/docs/01-getting-started/04-app-organization.md +++ b/docs/01-getting-started/04-app-organization.md @@ -19,7 +19,7 @@ However, when using the automatic mode for generating the structure, the documen You can initialize Robindoc on any subpath of your site, as long as you specify the [`basePath`](../02-structure/01-configuration.md) 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](../03-initialization.md) page. +After initialization, you will receive Sidebar, Page, getStaticParams, getMetadata, and getPageData. Read more on the [Initialization](../03-initialization.md) page. Global elements - [`RobinProvider`](../03-customization/01-elements/robin-provider.md), [`Header`](../03-customization/01-elements/header.md), [`Footer`](../03-customization/01-elements/footer.md), [`Containers`](../03-customization/01-elements/containers.md) and [`Sidebar`](../03-customization/01-elements/sidebar.md) - 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. @@ -28,11 +28,11 @@ Currently, Robindoc works only with the App Router. Once RSC is available for th Next.js supports dynamic routes, so it is recommended to set up one [dynamic segment](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#optional-catch-all-segments) for all documentation pages. -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="v14 TSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="v14 TSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; -const Page: React.FC<{ params }: { params: { path?: string[] } }> = async ({ params }) => { - const pathname = "/docs/" + (params.path?.join("/") || ""); +const Page: React.FC<{ params }: { params: { segments?: string[] } }> = async ({ params }) => { + const pathname = "/docs/" + (params.segments?.join("/") || ""); return ; }; @@ -40,11 +40,11 @@ const Page: React.FC<{ params }: { params: { path?: string[] } }> = async ({ par export default Page; ``` -```jsx filename="app/docs/[[...path]]/page.js" switcher tab="v14 JSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```jsx filename="app/docs/[[...segments]]/page.js" switcher tab="v14 JSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; const Page = async ({ params }) => { - const pathname = "/docs/" + (params.path?.join("/") || ""); + const pathname = "/docs/" + (params.segments?.join("/") || ""); return ; }; @@ -52,12 +52,12 @@ const Page = async ({ params }) => { export default Page; ``` -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="v15 TSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="v15 TSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; -const Page: React.FC<{ params }: { params: Promise<{ path?: string[] }> }> = async ({ params }) => { - const { path } = await params; - const pathname = "/docs/" + (path?.join("/") || ""); +const Page: React.FC<{ params }: { params: Promise<{ segments?: string[] }> }> = async ({ params }) => { + const { segments } = await params; + const pathname = "/docs/" + (segments?.join("/") || ""); return ; }; @@ -65,12 +65,12 @@ const Page: React.FC<{ params }: { params: Promise<{ path?: string[] }> }> = asy export default Page; ``` -```jsx filename="app/docs/[[...path]]/page.js" switcher tab="v15 JSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```jsx filename="app/docs/[[...segments]]/page.js" switcher tab="v15 JSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; const Page = async ({ params }) => { - const { path } = await params; - const pathname = "/docs/" + (path?.join("/") || ""); + const { segments } = await params; + const pathname = "/docs/" + (segments?.join("/") || ""); return ; }; @@ -82,85 +82,85 @@ For more details about the props, refer to the [`Page`](../03-customization/01-e You should also set up metadata generation and static parameters generation (if you want to use SSG, which is highly recommended): -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="v14 TSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="v14 TSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; // ... export const generateMetadata = async ({ params, }: { - params: { path?: string[] }; + params: { segments?: string[] }; }) => { - const pathname = "/docs/" + (params.path?.join("/") || ""); - const meta = await getMeta(pathname); + const pathname = "/docs/" + (params.segments?.join("/") || ""); + const metadata = await getMetadata(pathname); - return meta; + return metadata; }; export const generateStaticParams = async () => { - const pages = await getPages("/docs/"); - return pages.map((page) => ({ path: page.split("/").slice(2) })); + const staticParams = await getStaticParams("/docs/"); + return staticParams; }; ``` -```jsx filename="app/docs/[[...path]]/page.js" switcher tab="v14 JSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```jsx filename="app/docs/[[...segments]]/page.js" switcher tab="v14 JSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; // ... export const generateMetadata = async ({ params }) => { - const pathname = "/docs/" + (params.path?.join("/") || ""); - const meta = await getMeta(pathname); + const pathname = "/docs/" + (params.segments?.join("/") || ""); + const metadata = await getMetadata(pathname); - return meta; + return metadata; }; export const generateStaticParams = async () => { - const pages = await getPages("/docs/"); - return pages.map((page) => ({ path: page.split("/").slice(2) })); + const staticParams = await getStaticParams("/docs/"); + return staticParams; }; ``` -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="v15 TSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="v15 TSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; // ... export const generateMetadata = async ({ params, }: { - params: Promise<{ path?: string[] }>; + params: Promise<{ segments?: string[] }>; }) => { - const { path } = await params; - const pathname = "/docs/" + (path?.join("/") || ""); - const meta = await getMeta(pathname); + const { segments } = await params; + const pathname = "/docs/" + (segments?.join("/") || ""); + const metadata = await getMetadata(pathname); - return meta; + return metadata; }; export const generateStaticParams = async () => { - const pages = await getPages("/docs/"); - return pages.map((page) => ({ path: page.split("/").slice(2) })); + const staticParams = await getStaticParams("/docs/"); + return staticParams; }; ``` -```jsx filename="app/docs/[[...path]]/page.js" switcher tab="v15 JSX" -import { Page, Sidebar, getMeta, getPages } from "../robindoc"; +```jsx filename="app/docs/[[...segments]]/page.js" switcher tab="v15 JSX" +import { Page, Sidebar, getMetadata, getStaticParams } from "../robindoc"; // ... export const generateMetadata = async ({ params }) => { - const { path } = await params; - const pathname = "/docs/" + (path?.join("/") || ""); - const meta = await getMeta(pathname); + const { segments } = await params; + const pathname = "/docs/" + (segments?.join("/") || ""); + const metadata = await getMetadata(pathname); - return meta; + return metadata; }; export const generateStaticParams = async () => { - const pages = await getPages("/docs/"); - return pages.map((page) => ({ path: page.split("/").slice(2) })); + const staticParams = await getStaticParams("/docs/"); + return staticParams; }; ``` @@ -171,7 +171,7 @@ It is recommended to place the Robindoc initialization near this route. ```ts filename="app/docs/robindoc.ts" switcher tab="TypeScript" clone="js|JavaScript|app/docs/robindoc.js" import { initializeRobindoc } from "robindoc"; -export const { Page, Sidebar, getPages, getMeta, getPageContent } = +export const { Page, Sidebar, getStaticParams, getMetadata, getPageData } = initializeRobindoc({ configuration: { sourceRoot: "../docs", @@ -339,21 +339,21 @@ const nextConfig: NextConfig = { }; ``` -For more details on search configuration, refer to the [Search](../03-customization/03-search.md) page. +For more details on search configuration, refer to the [Search](../03-customization/04-search.md) page. ## Sitemap Setup -To generate a sitemap in next.js, you can use a [special sitemap file](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap) in combination with [getPages](../03-customization/02-tools/get-pages.md) tool: +To generate a sitemap in next.js, you can use a [special sitemap file](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap) in combination with [getStaticParams](../03-customization/02-tools/get-static-params.md) tool: ```ts filename="app/sitemap.ts" switcher tab="TypeScript" import { type MetadataRoute } from "next"; -import { getPages } from "./docs/robindoc"; +import { getStaticParams } from "./docs/robindoc"; const sitemap = async (): Promise => { - const pages = await getPages(); + const staticParams = await getStaticParams(); - return pages.map((page) => ({ - url: `https://robindoc.com${page}`, + return staticParams.map(({ segments }) => ({ + url: `https://robindoc.com${segments.join("/")}`, lastModified: new Date(), changeFrequency: "daily", priority: 0.7, @@ -365,13 +365,13 @@ export default sitemap; ```js filename="app/sitemap.js" switcher tab="JavaScript" import { type MetadataRoute } from "next"; -import { getPages } from "./docs/robindoc"; +import { getStaticParams } from "./docs/robindoc"; const sitemap = async () => { - const pages = await getPages(); + const staticParams = await getStaticParams(); - return pages.map((page) => ({ - url: `https://robindoc.com${page}`, + return staticParams.map(({ segments }) => ({ + url: `https://robindoc.com/${segments.join('/')}`, lastModified: new Date(), changeFrequency: "daily", priority: 0.7, diff --git a/docs/02-structure/02-items.md b/docs/02-structure/02-items.md index 6596fb43..13b925aa 100644 --- a/docs/02-structure/02-items.md +++ b/docs/02-structure/02-items.md @@ -135,7 +135,7 @@ export const { Page, Sidebar } = initializeRobindoc({ In automatic mode, Robindoc first looks for a `structure.json` file in the current directory. -If the `structure.json` file is not in the current directory, Robindoc will try to create the structure on its own based on the files in the directory. In this case, it will determine all paths, slugs, as well as the header for the sidebar link. The header is formed according to the same principles as the meta-header. Learn more about getting metadata on the [Get Meta](../03-customization/02-tools/get-meta.md) page. +If the `structure.json` file is not in the current directory, Robindoc will try to create the structure on its own based on the files in the directory. In this case, it will determine all paths, slugs, as well as the header for the sidebar link. The header is formed according to the same principles as the meta-header. Learn more about getting metadata on the [Get Meta](../03-customization/02-tools/get-metadata.md) page. ## structure.json diff --git a/docs/03-customization/01-elements/header.md b/docs/03-customization/01-elements/header.md index 0f9acf57..13ef56bf 100644 --- a/docs/03-customization/01-elements/header.md +++ b/docs/03-customization/01-elements/header.md @@ -38,7 +38,7 @@ All customization in Robindoc happens through the structure and props of the com `links` [`{ title: string; href: string }[]`] - a list of links to pages on your site unrelated to the documentation section. This could include blog, showcases, about, etc.; -`searcher` - the route for search functionality or a client-side async callback. If this field is not provided, search functionality will not be available. Read more on the "[Search](../03-search.md)" page; +`searcher` - the route for search functionality or a client-side async callback. If this field is not provided, search functionality will not be available. Read more on the "[Search](../04-search.md)" page; `translations` [`{ [key: string]: string }`] - translations for the current block. The key is the term identifier, and the value is the corresponding translation. _For the latest list of terms, check the editor hints_; diff --git a/docs/03-customization/02-tools/README.md b/docs/03-customization/02-tools/README.md index 1dfe3598..de450ae1 100644 --- a/docs/03-customization/02-tools/README.md +++ b/docs/03-customization/02-tools/README.md @@ -7,7 +7,7 @@ These utilities work based on the structure and documentation files. They are ne ```ts filename="app/docs/robindoc.ts" switcher tab="TypeScript" clone="js|JavaScript|app/docs/robindoc.js" import { initializeRobindoc } from "robindoc"; -export const { Page, Sidebar, getPages, getMeta, getPageContent } = +export const { Page, Sidebar, getStaticParams, getMetadata, getPageData } = initializeRobindoc({ configuration: { sourceRoot: "../docs", @@ -18,4 +18,4 @@ export const { Page, Sidebar, getPages, getMeta, getPageContent } = }); ``` -For more information on using the utilities, refer to their respective pages - [`getMeta`](./get-meta.md), [`getPages`](./get-pages.md), [`getPageContent`](./get-page-content.md). +For more information on using the utilities, refer to their respective pages - [`getMetadata`](./get-metadata.md), [`getStaticParams`](./get-static-params.md), [`getPageData`](./get-page-data.md). diff --git a/docs/03-customization/02-tools/get-meta.md b/docs/03-customization/02-tools/get-meta.md deleted file mode 100644 index 4e66f316..00000000 --- a/docs/03-customization/02-tools/get-meta.md +++ /dev/null @@ -1,55 +0,0 @@ -# Get Meta - -`getMeta` generates a metadata object for the current structure (including those automatically generated during initialization). - -## Metadata Generation - -To collect metadata, Robindoc supports front-matter: - -```markdown filename="README.md" ---- -title: "Get Meta | Robindoc" -description: "Robindoc AAAAAA" ---- -``` - -If you do not provide a front-matter title, the first-level heading of the page will be used as the title. - -## Usage - -`getMeta` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). - -For more details on using the utility in your application, refer to the section [App Organization](../../01-getting-started/04-app-organization.md). - -You can get the metadata object for a specific page using the following method: - -```tsx filename="app/docs/page.tsx" switcher tab="TypeScript" -import { getMeta } from "./robindoc"; - -export const generateMetadata = async ({ - params, -}: { - params: { path?: string[] }; -}) => { - const pathname = "/docs/" + (params.path?.join("/") || ""); - const meta = await getMeta(pathname); - - return meta; -}; -``` - -```jsx filename="app/docs/page.jsx" switcher tab="JavaScript" -import { getMeta } from "./robindoc"; - -export const generateMetadata = async ({ params }) => { - const { path } = await params; - const pathname = "/docs/" + (path?.join("/") || ""); - const meta = await getMeta(pathname); - - return meta; -}; -``` - -## Arguments - -`pathname` - the full path of the current page (e.g., `/docs/02-tools/get-meta`) must be provided to obtain the metadata. diff --git a/docs/03-customization/02-tools/get-metadata.md b/docs/03-customization/02-tools/get-metadata.md new file mode 100644 index 00000000..95c3390d --- /dev/null +++ b/docs/03-customization/02-tools/get-metadata.md @@ -0,0 +1,55 @@ +# Get Metadata + +`getMetadata` generates a metadata object for the current structure (_including those automatically generated during initialization_). + +## Metadata Generation + +To collect metadata, Robindoc supports front-matter: + +```markdown filename="README.md" +--- +title: "Get Metadata | Robindoc" +description: "Robindoc AAAAAA" +--- +``` + +If you do not provide a front-matter title, the first-level heading of the page will be used as the title. + +## Usage + +`getMetadata` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). + +For more details on using the utility in your application, refer to the section [App Organization](../../01-getting-started/04-app-organization.md). + +You can get the metadata object for a specific page using the following method: + +```tsx filename="app/docs/page.tsx" switcher tab="TypeScript" +import { getMetadata } from "./robindoc"; + +export const generateMetadata = async ({ + params, +}: { + params: { segments?: string[] }; +}) => { + const pathname = "/docs/" + (params.segments?.join("/") || ""); + const metadata = await getMetadata(pathname); + + return metadata; +}; +``` + +```jsx filename="app/docs/page.jsx" switcher tab="JavaScript" +import { getMetadata } from "./robindoc"; + +export const generateMetadata = async ({ params }) => { + const { segments } = await params; + const pathname = "/docs/" + (segments?.join("/") || ""); + const metadata = await getMetadata(pathname); + + return metadata; +}; +``` + +## Arguments + +`pathname` - the full path of the current page (f.e., `/docs/02-tools/get-metadata`) must be provided to obtain the metadata. diff --git a/docs/03-customization/02-tools/get-page-content.md b/docs/03-customization/02-tools/get-page-content.md deleted file mode 100644 index 9c9e245c..00000000 --- a/docs/03-customization/02-tools/get-page-content.md +++ /dev/null @@ -1,22 +0,0 @@ -# Get Page Content - -`getPageContent` is a utility that returns the markdown document and its title (generated for the structure). - -## Usage - -`getPageContent` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). - -It can be used, for example, for search functionality. For more details on general search configuration, refer to the [Search](../03-search.md) page. For Next.js-specific setup, refer to the [App Organization](../../01-getting-started/04-app-organization.md) page. - -```ts filename="app/api/search/route.ts" switcher tab="TypeScript" clone="js|JavaScript|app/api/search/route.js" -const searchResults = []; -const { content, title } = await getPageContent("/docs/introduction"); - -if (content.includes(search)) { - searchResults.push({ href: "/docs/introduction", content, title }); -} -``` - -## Arguments - -`pathname` - the full path of the current page (e.g., `/docs/introduction`) must be provided to obtain the page data. diff --git a/docs/03-customization/02-tools/get-page-data.md b/docs/03-customization/02-tools/get-page-data.md new file mode 100644 index 00000000..a2351c6d --- /dev/null +++ b/docs/03-customization/02-tools/get-page-data.md @@ -0,0 +1,22 @@ +# Get Page Data + +`getPageData` is a utility that returns the markdown document and its title (generated for the structure). + +## Usage + +`getPageData` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). + +It can be used, for example, for search functionality. For more details on general search configuration, refer to the [Search](../04-search.md) page. For Next.js-specific setup, refer to the [App Organization](../../01-getting-started/04-app-organization.md) page. + +```ts filename="app/api/search/route.ts" switcher tab="TypeScript" clone="js|JavaScript|app/api/search/route.js" +const searchResults = []; +const { raw, title } = await getPageData("/docs/introduction"); + +if (raw.includes(search)) { + searchResults.push({ href: "/docs/introduction", raw, title }); +} +``` + +## Arguments + +`pathname` - the full path of the current page (f.e., `/docs/introduction`) must be provided to obtain the page data. diff --git a/docs/03-customization/02-tools/get-pages.md b/docs/03-customization/02-tools/get-pages.md deleted file mode 100644 index 06a254d1..00000000 --- a/docs/03-customization/02-tools/get-pages.md +++ /dev/null @@ -1,28 +0,0 @@ -# Get Pages - -`getPages` allows you to retrieve a list of all pages for the current structure (including those automatically generated). - -## Usage - -`getPages` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). - -For more details on using the utility in your application, refer to the [App Organization](../../01-getting-started/04-app-organization.md) page. - -You can obtain an array of objects with the list of segments for each page using the following method: - -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="TypeScript" clone="jsx|JavaScript|app/docs/[[...path]]/page.jsx" -import { getPages } from "./robindoc"; - -export const generateStaticParams = async () => { - const pages = await getPages(); - return pages.map((page) => ({ path: page.split("/").slice(2) })); -}; -``` - -## Arguments - -In some cases, you might want to retrieve a specific section of the documentation, such as `/docs` or `/blog`. To get a filtered list of pages, simply pass the desired prefix as an argument. - -```tsx filename="app/docs/[[...path]]/page.tsx" switcher tab="TypeScript" clone="jsx|JavaScript|app/docs/[[...path]]/page.jsx" -const pages = await getPages("/docs"); -``` diff --git a/docs/03-customization/02-tools/get-static-params.md b/docs/03-customization/02-tools/get-static-params.md new file mode 100644 index 00000000..ba64c671 --- /dev/null +++ b/docs/03-customization/02-tools/get-static-params.md @@ -0,0 +1,34 @@ +# Get Static Params + +`getStaticParams` allows you to retrieve a list of all pages for the current structure (including those automatically generated). + +## Usage + +`getStaticParams` is obtained as a result of [initializing Robindoc](../../01-getting-started/03-initialization.md). + +For more details on using the utility in your application, refer to the [App Organization](../../01-getting-started/04-app-organization.md) page. + +You can obtain an array of objects with the list of segments for each page using the following method: + +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="TypeScript" clone="jsx|JavaScript|app/docs/[[...segments]]/page.jsx" +import { getStaticParams } from "./robindoc"; + +export const generateStaticParams = async () => { + const staticParams = await getStaticParams(); + return staticParams; +}; +``` + +## Arguments + +In some cases, you might want to retrieve a specific section of the documentation, such as `/docs` or `/blog`. To get a filtered list of pages, simply pass the desired `prefix` as an argument. + +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="TypeScript" clone="jsx|JavaScript|app/docs/[[...segments]]/page.jsx" +const staticParams = await getStaticParams("/docs"); +``` + +Also in some situations you may need a different key for the parameter (the default and recommended is `segments`). In such situations, pass the name of the dynamic parameter as the second argument (`segmentsParamKey`): + +```tsx filename="app/docs/[[...segments]]/page.tsx" switcher tab="TypeScript" clone="jsx|JavaScript|app/docs/[[...segments]]/page.jsx" +const staticParams = await getStaticParams("/docs", "path"); +``` diff --git a/docs/03-customization/04-search.md b/docs/03-customization/04-search.md index 1cc94818..6ea75b65 100644 --- a/docs/03-customization/04-search.md +++ b/docs/03-customization/04-search.md @@ -7,7 +7,7 @@ You can configure search in two ways: by providing the path to the search API ro To use an API route for search, pass the path to the search endpoint in the `searcher` prop of the [`Header`](./01-elements/header.md) component. The search API should return an array of results with the following keys: - `title` - the title of the page (e.g., `Introduction`, `Search`); -- `href` - the link to the page (e.g., `/docs/introduction`, `/docs/03-search`); +- `href` - the link to the page (e.g., `/docs/introduction`, `/docs/04-search`); - `description` - an optional additional field with search results related to the page content. Here’s an example of how to configure the `Header` component with a search API route: @@ -58,11 +58,11 @@ export const searcher = async (search, abortController) => { ## API Route Example -If you use an API route, the server should handle the search requests. The following code demonstrates a simple search implementation using the `match-sorter` library and the utilities `getPages` and `getPageContent`: +If you use an API route, the server should handle the search requests. The following code demonstrates a simple search implementation using the `match-sorter` library and the utilities `getStaticParams` and `getPageData`: ```ts filename="app/api/search/route.ts" switcher tab="TypeScript" import { matchSorter } from "match-sorter"; -import { getPages, getPageContent } from "../docs/robindoc"; +import { getStaticParams, getPageData } from "../docs/robindoc"; export const GET = async (request: Request) => { const url = new URL(request.url); @@ -73,16 +73,17 @@ export const GET = async (request: Request) => { if (!search) return new Response(JSON.stringify([]), { headers }); - const pages = await getPages(); - const docs: { href: string; content: string; title: string }[] = []; + const staticParams = await getStaticParams(); + const docs: { href: string; raw: string; title: string }[] = []; - for await (const page of pages) { - const { content, title } = await getPageContent(page); - docs.push({ href: page, content, title }); + for await (const staticParam of staticParams) { + const pathname = `/${staticParam.segments.join("/")}`; + const { raw, title } = await getPageData(pathname); + docs.push({ href: pathname, raw, title }); } const matchResults = matchSorter(docs, search, { - keys: ["content", "title"], + keys: ["raw", "title"], }); const searchResults = matchResults .slice(0, 5) @@ -94,7 +95,7 @@ export const GET = async (request: Request) => { ```js filename="app/api/search/route.js" switcher tab="JavaScript" import { matchSorter } from "match-sorter"; -import { getPages, getPageContent } from "../docs/robindoc"; +import { getStaticParams, getPageData } from "../docs/robindoc"; export const GET = async (request) => { const url = new URL(request.url); @@ -105,16 +106,17 @@ export const GET = async (request) => { if (!search) return new Response(JSON.stringify([]), { headers }); - const pages = await getPages(); + const staticParams = await getStaticParams(); const docs = []; - for await (const page of pages) { - const { content, title } = await getPageContent(page); - docs.push({ href: page, content, title }); + for await (const staticParam of staticParams) { + const pathname = `/${staticParam.segments.join("/")}`; + const { raw, title } = await getPageData(pathname); + docs.push({ href: pathname, raw, title }); } const matchResults = matchSorter(docs, search, { - keys: ["content", "title"], + keys: ["raw", "title"], }); const searchResults = matchResults .slice(0, 5) diff --git a/packages/robindoc/package.json b/packages/robindoc/package.json index 1ab969d8..1b5f4e1f 100644 --- a/packages/robindoc/package.json +++ b/packages/robindoc/package.json @@ -1,6 +1,6 @@ { "name": "robindoc", - "version": "2.5.1", + "version": "3.0.0", "description": "", "main": "./lib/index.js", "scripts": { @@ -13,7 +13,13 @@ "assets" ], "keywords": [ - "documentation" + "documentation", + "genearation", + "SSG", + "next.js", + "RSC", + "docs", + "markdown" ], "repository": { "type": "git", diff --git a/packages/robindoc/src/components/blocks/contents/index.tsx b/packages/robindoc/src/components/blocks/contents/index.tsx index eba5e62e..f9a7c0b9 100644 --- a/packages/robindoc/src/components/blocks/contents/index.tsx +++ b/packages/robindoc/src/components/blocks/contents/index.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef } from "react"; import clsx from "clsx"; import { useHeadingIndex } from "@src/components/contexts/contents/use-heading-index"; -import { detectGitType } from "@src/core/utils/git-data"; +import { detectGitType } from "@src/core/utils/git-tools"; import "./contents.scss"; diff --git a/packages/robindoc/src/components/blocks/header-social/index.tsx b/packages/robindoc/src/components/blocks/header-social/index.tsx index 696c8f51..d41d0724 100644 --- a/packages/robindoc/src/components/blocks/header-social/index.tsx +++ b/packages/robindoc/src/components/blocks/header-social/index.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { detectGitType } from "@src/core/utils/git-data"; +import { detectGitType } from "@src/core/utils/git-tools"; import { GithubLogo, GitlabLogo, GitLogo } from "@src/components/ui/git-logos"; import "./header-social.scss"; diff --git a/packages/robindoc/src/components/elements/article/utils.ts b/packages/robindoc/src/components/elements/article/utils.ts index 39cbed8d..fcf35dd8 100644 --- a/packages/robindoc/src/components/elements/article/utils.ts +++ b/packages/robindoc/src/components/elements/article/utils.ts @@ -4,6 +4,8 @@ import { lexer, type Tokens, type Token } from "marked"; import { dirname, join } from "path"; import { type BlockquoteType } from "@src/components/ui/blockquote"; +import { parseTokenText } from "@src/core/utils/content-tools"; + import { type PagesType } from "./types"; export type AnchorData = { @@ -13,20 +15,6 @@ export type AnchorData = { token: Token; }; -export const parseTokenText = (token: Token): string => { - if (!token) return ""; - - if ("tokens" in token) { - return token.tokens?.map((el) => parseTokenText(el)).join("") || ""; - } - - if ("raw" in token) { - return token.raw; - } - - return ""; -}; - export const parseMarkdown = (content: string) => { const { content: matterContent } = matter(content); const tokens = lexer(matterContent.trim()); diff --git a/packages/robindoc/src/components/ui/blockquote/index.tsx b/packages/robindoc/src/components/ui/blockquote/index.tsx index ed7d3c5b..873dbe5e 100644 --- a/packages/robindoc/src/components/ui/blockquote/index.tsx +++ b/packages/robindoc/src/components/ui/blockquote/index.tsx @@ -13,7 +13,8 @@ interface BlockquoteProps { } export const Blockquote: React.FC> = ({ className, type, children }) => { - const { icon: Icon, title } = type && type in TYPES_DATA ? TYPES_DATA[type] : {}; + const { icon: Icon, title } = + type && type in TYPES_DATA ? TYPES_DATA[type] : ({} as { icon: undefined; title: undefined }); return (
diff --git a/packages/robindoc/src/components/ui/tabs/tabs-header/index.tsx b/packages/robindoc/src/components/ui/tabs/tabs-header/index.tsx index 21837995..9b198608 100644 --- a/packages/robindoc/src/components/ui/tabs/tabs-header/index.tsx +++ b/packages/robindoc/src/components/ui/tabs/tabs-header/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import clsx from "clsx"; -import { saveTab } from "@src/core/utils/tabs-store"; +import { saveTab } from "@src/core/utils/tabs-tools"; export interface TabsHeaderProps { tabs: { name: string; id: string }[]; diff --git a/packages/robindoc/src/core/utils/content-tools.ts b/packages/robindoc/src/core/utils/content-tools.ts new file mode 100644 index 00000000..3c8a0f03 --- /dev/null +++ b/packages/robindoc/src/core/utils/content-tools.ts @@ -0,0 +1,19 @@ +import { type Token } from "marked"; + +export const parseTokenText = (token: Token): string => { + if (!token) return ""; + + if ("tokens" in token) { + return token.tokens?.map((el) => parseTokenText(el)).join("") || ""; + } + + if ("text" in token) { + return token.text; + } + + if ("raw" in token) { + return token.raw; + } + + return ""; +}; diff --git a/packages/robindoc/src/core/utils/get-meta.ts b/packages/robindoc/src/core/utils/get-metadata.ts similarity index 68% rename from packages/robindoc/src/core/utils/get-meta.ts rename to packages/robindoc/src/core/utils/get-metadata.ts index 53d9e15c..95e45521 100644 --- a/packages/robindoc/src/core/utils/get-meta.ts +++ b/packages/robindoc/src/core/utils/get-metadata.ts @@ -1,19 +1,21 @@ -import { type BaseProvider } from "../providers/base"; import matter from "gray-matter"; import { lexer, Tokens } from "marked"; import { set } from "dot-prop"; + +import { type BaseProvider } from "../providers/base"; import { loadContent } from "./load-content"; +import { parseTokenText } from "./content-tools"; -type GetMetaOptions = +type GetMetadataOptions = | { uri: string; provider?: BaseProvider; content?: undefined } | { uri?: undefined; provider?: undefined; content: string }; -export const getMeta = async (opts: GetMetaOptions) => { +export const getMetadata = async (opts: GetMetadataOptions) => { const { uri, provider, content } = opts; const { data } = uri ? await loadContent(uri, provider) : { data: content }; if (!data) { - throw new Error("Robindoc: Please provide content or valid uri"); + throw new Error("Robindoc: Please provide content or valid URI"); } const { content: matterContent, data: matterData } = matter(data); @@ -21,8 +23,8 @@ export const getMeta = async (opts: GetMetaOptions) => { const robinData = Object.entries(tree.links).reduce>((acc, cur) => { const [key, value] = cur; - const metaKey = key.startsWith("robin.") && key.replace("robin.", ""); const content = value.title; + const metaKey = key.startsWith("robin.") && key.substring(6); if (content && metaKey) { set(acc, metaKey, content); @@ -34,7 +36,14 @@ export const getMeta = async (opts: GetMetaOptions) => { if (!robinData.title) { const pageHeading = tree.find((el) => el.type === "heading" && el.depth === 1) as Tokens.Heading | undefined; if (pageHeading?.text) { - robinData.title = pageHeading.text; + robinData.title = parseTokenText(pageHeading); + } + } + + if (!robinData.description) { + const firstParagraph = tree.find((el) => el.type === "paragraph") as Tokens.Heading | undefined; + if (firstParagraph?.text) { + robinData.description = parseTokenText(firstParagraph); } } diff --git a/packages/robindoc/src/core/utils/git-data.ts b/packages/robindoc/src/core/utils/git-tools.ts similarity index 100% rename from packages/robindoc/src/core/utils/git-data.ts rename to packages/robindoc/src/core/utils/git-tools.ts diff --git a/packages/robindoc/src/core/utils/initialize-robindoc.tsx b/packages/robindoc/src/core/utils/initialize-robindoc.tsx index 7aa6a7d9..12529a12 100644 --- a/packages/robindoc/src/core/utils/initialize-robindoc.tsx +++ b/packages/robindoc/src/core/utils/initialize-robindoc.tsx @@ -1,11 +1,13 @@ import React from "react"; + import { Article as ArticleBase, type ArticleProps as ArticlePropsBase } from "@src/components/elements/article"; import { Sidebar as SidebarBase, type SidebarProps as SidebarPropsBase } from "@src/components/elements/sidebar"; + import { type Structure } from "../types/structure"; import { parseStructure } from "./parse-structure"; import { getConfiguration } from "./get-configuration"; -import { getMeta as getMetaBase } from "./get-meta"; -import { normalizePathname } from "./path-tools"; +import { getMetadata as getMetadataBase } from "./get-metadata"; +import { normalizePathname, removeTrailingSlash } from "./path-tools"; import { loadContent } from "./load-content"; type PageProps = Omit, "uri" | "content" | "provider" | "pathname" | "pages"> & { @@ -23,28 +25,27 @@ const loadStructure = async (structureTemplate: Structure | (() => Structure | P }; export const initializeRobindoc = (structureTemplate: Structure | (() => Structure | Promise)) => { - const pageDataPromise = loadStructure(structureTemplate).then((structure) => + const structureParsedPromise = loadStructure(structureTemplate).then((structure) => parseStructure(structure.items || [], getConfiguration(structure.configuration || {})), ); const Page: React.FC = async ({ pathname, ...props }) => { - const { pages } = await pageDataPromise; - const pathnameClean = normalizePathname(pathname); - const pageData = pages[pathnameClean]; + const { pages } = await structureParsedPromise; + const pathnameNormalized = normalizePathname(pathname); + const pageInstruction = pages[pathnameNormalized]; - if (!pageData) { - throw new Error(`Can not find data for "${pathnameClean}". Please check structure`); + if (!pageInstruction) { + throw new Error(`Can not find data for "${pathnameNormalized}". Please check structure`); } const paths = Object.keys(pages); - const targetPageIndex = paths.indexOf(pathnameClean); - const prevPagePathname = targetPageIndex > 0 && paths[targetPageIndex - 1]; - const nextPagePathname = - targetPageIndex !== -1 && targetPageIndex < paths.length - 1 && paths[targetPageIndex + 1]; + const targetPageIndex = paths.indexOf(pathnameNormalized); + const prevPagePathname = paths[targetPageIndex - 1]; + const nextPagePathname = targetPageIndex < paths.length - 1 && paths[targetPageIndex + 1]; const prev = prevPagePathname && { pathname: prevPagePathname, title: pages[prevPagePathname].title }; const next = nextPagePathname && { pathname: nextPagePathname, title: pages[nextPagePathname].title }; - const breadcrumbs = pageData.crumbs.map((crumb) => ({ title: pages[crumb].title, pathname: crumb })); + const breadcrumbs = pageInstruction.crumbs.map((crumb) => ({ title: pages[crumb].title, pathname: crumb })); const clientPages = Object.entries(pages).reduce<{ clientPath: string; origPath: string }[]>( (acc, [clientPath, { origPath }]) => { if (origPath) acc.push({ clientPath, origPath }); @@ -55,10 +56,10 @@ export const initializeRobindoc = (structureTemplate: Structure | (() => Structu return ( Structu }; const Sidebar: React.FC = async (props) => { - const { tree } = await pageDataPromise; + const { tree } = await structureParsedPromise; return ; }; - const getPages = async (basePath?: string) => { - const { pages } = await pageDataPromise; + const getStaticParams = async ( + prefix: string = "", + segmentsParamKey: T = "segments" as T, + ) => { + const { pages } = await structureParsedPromise; const pagesArr = Object.keys(pages); - if (basePath) return pagesArr.filter((page) => page.startsWith(basePath)); - return pagesArr; + const prefixWithoutTrailingSlash = removeTrailingSlash(prefix); + + return pagesArr.reduce[]>((acc, cur) => { + if (!cur.startsWith(prefixWithoutTrailingSlash)) return acc; + + acc.push({ + [segmentsParamKey]: cur.substring(prefixWithoutTrailingSlash.length + 1).split("/"), + } as Record); + + return acc; + }, []); }; - const getMeta = async (pathname: string) => { - const { pages } = await pageDataPromise; - const pathnameClean = normalizePathname(pathname); - const pageData = pages[pathnameClean]; - if (!pageData) { - throw new Error(`Can not find data for "${pathnameClean}". Please check structure`); + const getMetadata = async (pathname: string) => { + const { pages } = await structureParsedPromise; + const pathnameNormalized = normalizePathname(pathname); + const pageInstruction = pages[pathnameNormalized]; + + if (!pageInstruction) { + throw new Error(`Can not find data for "${pathnameNormalized}". Please check structure`); } - const meta = await getMetaBase({ - uri: pageData.uri, - provider: pageData.configuration.provider, + + const metadata = await getMetadataBase({ + uri: pageInstruction.uri, + provider: pageInstruction.configuration.provider, }); - return meta; + return metadata; }; - const getPageContent = async (pathname: string) => { - const { pages } = await pageDataPromise; - const pathnameClean = normalizePathname(pathname); - const pageData = pages[pathnameClean]; + const getPageData = async (pathname: string) => { + const { pages } = await structureParsedPromise; + const pathnameNormalized = normalizePathname(pathname); + const pageInstruction = pages[pathnameNormalized]; - if (!pageData) { - throw new Error(`Can not find data for "${pathnameClean}". Please check structure`); + if (!pageInstruction) { + throw new Error(`Can not find data for "${pathnameNormalized}". Please check structure`); } - const title = pageData.title; - const { data } = await loadContent(pageData.uri, pageData.configuration.provider); + const title = pageInstruction.title; + const { data } = await loadContent(pageInstruction.uri, pageInstruction.configuration.provider); - return { title, content: data }; + return { title, raw: data }; }; - const getPageData = async (pathname: string) => { - const { pages } = await pageDataPromise; - const pathnameClean = normalizePathname(pathname); - const pageData = pages[pathnameClean]; + const getPageInstruction = async (pathname: string) => { + const { pages } = await structureParsedPromise; + const pathnameNormalized = normalizePathname(pathname); + const pageInstruction = pages[pathnameNormalized]; - if (!pageData) { - throw new Error(`Can not find data for "${pathnameClean}". Please check structure`); + if (!pageInstruction) { + throw new Error(`Can not find data for "${pathnameNormalized}". Please check structure`); } - return pageData; + return pageInstruction; }; - return { Page, Sidebar, getPages, getMeta, getPageContent, getPageData }; + return { Page, Sidebar, getStaticParams, getMetadata, getPageData, getPageInstruction }; }; diff --git a/packages/robindoc/src/core/utils/load-content.ts b/packages/robindoc/src/core/utils/load-content.ts index 95369920..975c58dc 100644 --- a/packages/robindoc/src/core/utils/load-content.ts +++ b/packages/robindoc/src/core/utils/load-content.ts @@ -7,6 +7,7 @@ export const loadContent = async (uri: string, providerArg?: BaseProvider, root? const content = await providerArg.load(uri); return { data: content, type: providerArg.type, provider: providerArg }; } + if (uri.startsWith("https://github.com/")) { const provider = new GithubProvider(uri); if (provider.pathname) { @@ -16,6 +17,7 @@ export const loadContent = async (uri: string, providerArg?: BaseProvider, root? throw new Error("Can not load content"); } } + if (uri.match(/https?:\/\//)) { const resp = await fetch(uri); if (!resp.ok) { diff --git a/packages/robindoc/src/core/utils/parse-structure.ts b/packages/robindoc/src/core/utils/parse-structure.ts index 9eb96cc3..8880fffd 100644 --- a/packages/robindoc/src/core/utils/parse-structure.ts +++ b/packages/robindoc/src/core/utils/parse-structure.ts @@ -2,7 +2,7 @@ import { type DocItem } from "../types/structure"; import { type Pages, type Crumbs, type Configuration } from "../types/content"; import { type TreeItem } from "../../components/elements/sidebar/types"; import { getConfiguration } from "./get-configuration"; -import { getMeta } from "./get-meta"; +import { getMetadata } from "./get-metadata"; import { generatePseudoTitle, checkIsLinkExternal, mergePathname, normalizePathname } from "./path-tools"; import { loadContent } from "./load-content"; @@ -114,8 +114,8 @@ const parseAutoStructure = async ( const pathname = mergePathname(parentConfiguration.basePath, clientPath); const pathnameNormalized = normalizePathname(pathname); - const meta = await getMeta({ provider: parentConfiguration.provider, uri: clientPath }); - const title = meta.title || generatePseudoTitle(pathnameNormalized); + const metadata = await getMetadata({ provider: parentConfiguration.provider, uri: clientPath }); + const title = metadata.title || generatePseudoTitle(pathnameNormalized); const origPath = await parentConfiguration.provider?.getPageSourcePathname(clientPath, pathnameNormalized); if (origPath) { pages[pathnameNormalized] = { @@ -248,10 +248,10 @@ export const parseStructure = async ( nestingLevel: number = 0, ) => { if (items === "auto") { - const structureData = await parseAutoStructure(parentConfiguration, crumbs, pathname, nestingLevel); - return structureData; + const structureParsed = await parseAutoStructure(parentConfiguration, crumbs, pathname, nestingLevel); + return structureParsed; } - const structureData = await parseStaticStructure(items, parentConfiguration, crumbs, pathname, nestingLevel); - return structureData; + const structureParsed = await parseStaticStructure(items, parentConfiguration, crumbs, pathname, nestingLevel); + return structureParsed; }; diff --git a/packages/robindoc/src/core/utils/path-tools.ts b/packages/robindoc/src/core/utils/path-tools.ts index 2716344d..063a5a23 100644 --- a/packages/robindoc/src/core/utils/path-tools.ts +++ b/packages/robindoc/src/core/utils/path-tools.ts @@ -1,24 +1,39 @@ -export const getFileUrl = (path: string) => { - const [, filename, ext] = path.match(/(?:^|\/)([^/]+)(\.mdx?)$/) || []; +export const getFileUrl = (pathname: string) => { + const [, filename, ext] = pathname.match(/(?:^|\/)([^/]+)(\.mdx?)$/) || []; - const clientPath = path.replace(new RegExp(`((\/|^)(readme|README|index|${filename}/${filename}))?${ext}$`), ""); + const clientPath = pathname.replace( + new RegExp(`((\/|^)(readme|README|index|${filename}/${filename}))?${ext}$`), + "", + ); return clientPath; }; -export const normalizePathname = (path?: string | null) => { - if (!path) return "/"; +export const normalizePathname = (pathname?: string | null) => { + if (!pathname) return "/"; - return path.replace(/\/$/, "") || "/"; + return pathname.replace(/\/$/, "") || "/"; }; -export const generatePseudoTitle = (path?: string | null) => { - const pathname = normalizePathname(path); - const pathnameSegments = pathname.split("/").filter(Boolean); +export const removeTrailingSlash = (pathname?: string | null) => { + if (!pathname) return ""; - if (pathnameSegments.length === 0) return "Index"; + return pathname.endsWith("/") ? pathname.substring(0, pathname.length - 1) : pathname; +}; + +export const addTrailingSlash = (pathname?: string | null) => { + if (!pathname) return ""; + + return pathname.endsWith("/") ? pathname : pathname + "/"; +}; + +export const generatePseudoTitle = (pathname?: string | null) => { + const pathnamename = normalizePathname(pathname); + const pathnamenameSegments = pathnamename.split("/").filter(Boolean); + + if (pathnamenameSegments.length === 0) return "Index"; - const lastSegment = pathnameSegments[pathnameSegments.length - 1]; + const lastSegment = pathnamenameSegments[pathnamenameSegments.length - 1]; const lastSegmentWords = lastSegment.split("-"); return lastSegmentWords.map((word) => word[0].toUpperCase() + word.substring(1)).join(" "); }; diff --git a/packages/robindoc/src/core/utils/tabs-store.ts b/packages/robindoc/src/core/utils/tabs-tools.ts similarity index 100% rename from packages/robindoc/src/core/utils/tabs-store.ts rename to packages/robindoc/src/core/utils/tabs-tools.ts diff --git a/site/src/app/api/search/route.ts b/site/src/app/api/search/route.ts index 8f0d2687..2423e385 100644 --- a/site/src/app/api/search/route.ts +++ b/site/src/app/api/search/route.ts @@ -1,5 +1,6 @@ import { matchSorter } from 'match-sorter' -import { getPages, getPageContent } from '../../docs/robindoc'; + +import { getStaticParams, getPageData } from '../../docs/robindoc'; const headers = new Headers(); headers.set('Content-Type', 'application/json; charset=UTF-8'); @@ -10,15 +11,16 @@ export const GET = async (request: Request) => { if (!search) return new Response(JSON.stringify([]), { headers }); - const pages = await getPages(); - const docs: { href: string; content: string; title: string }[] = []; + const staticParams = await getStaticParams(); + const docs: { href: string; raw: string; title: string }[] = []; - for await (const page of pages) { - const { content, title } = await getPageContent(page); - docs.push({ href: page, content, title }); + for await (const staticParam of staticParams) { + const pathname = `/${staticParam.segments.join('/')}`; + const { raw, title } = await getPageData(pathname); + docs.push({ href: pathname, raw, title }); } - const searchResults = matchSorter(docs, search, { keys: ['content', 'title'] }); + const searchResults = matchSorter(docs, search, { keys: ['raw', 'title'] }); return new Response( JSON.stringify(searchResults.slice(0, 5).map(item => ({ title: item.title, href: item.href }))), diff --git a/site/src/app/docs/[[...path]]/page.tsx b/site/src/app/docs/[[...path]]/page.tsx deleted file mode 100644 index be16bf5b..00000000 --- a/site/src/app/docs/[[...path]]/page.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Page, getMeta, getPageData, getPages } from "../robindoc"; -import { Note } from "../../../components/ui/note"; -import { PackageLinks } from "../../../components/ui/package-links"; - -const Docs = async ({ params }: { params: Promise<{ path?: string[] }> }) => { - const { path } = await params; - const pathname = '/docs/' + (path?.join('/') || ''); - const pageData = await getPageData(pathname); - - return ( - - ); -} - -export const generateMetadata = async ({ params }: { params: Promise<{ path?: string[] }> }) => { - const { path } = await params; - const pathname = '/docs/' + (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) })); -} - -export default Docs; diff --git a/site/src/app/docs/[[...segments]]/page.tsx b/site/src/app/docs/[[...segments]]/page.tsx new file mode 100644 index 00000000..93e68401 --- /dev/null +++ b/site/src/app/docs/[[...segments]]/page.tsx @@ -0,0 +1,37 @@ +import { Page, getMetadata, getPageInstruction, getStaticParams } from "../robindoc"; +import { Note } from "../../../components/ui/note"; +import { PackageLinks } from "../../../components/ui/package-links"; + +const Docs = async ({ params }: { params: Promise<{ segments?: string[] }> }) => { + const { segments } = await params; + const pathname = '/docs/' + (segments?.join('/') || ''); + const pageInstriction = await getPageInstruction(pathname); + + return ( + + ); +} + +export const generateMetadata = async ({ params }: { params: Promise<{ segments?: string[] }> }) => { + const { segments } = await params; + const pathname = '/docs/' + (segments?.join('/') || ''); + const metadata = await getMetadata(pathname); + return metadata; +}; + +export const generateStaticParams = async () => { + const staticParams = await getStaticParams('/docs'); + return staticParams; +} + +export default Docs; diff --git a/site/src/app/docs/robindoc.ts b/site/src/app/docs/robindoc.ts index a1f82a91..e2f65c20 100644 --- a/site/src/app/docs/robindoc.ts +++ b/site/src/app/docs/robindoc.ts @@ -1,8 +1,7 @@ import { initializeRobindoc } from "robindoc"; -export const { Page, Sidebar, getPages, getMeta, getPageContent, getPageData } = initializeRobindoc({ +export const { Page, Sidebar, getStaticParams, getMetadata, getPageData, getPageInstruction } = initializeRobindoc({ configuration: { - // sourceRoot: 'https://github.com/vordgi/robindoc/tree/main/docs', sourceRoot: '../docs', basePath: '/docs', gitToken: process.env.GIT_TOKEN, @@ -14,7 +13,6 @@ export const { Page, Sidebar, getPages, getMeta, getPageContent, getPageData } = type: 'heading', href: '/', configuration: { - // sourceRoot: 'https://github.com/vordgi/robindoc/tree/main/README.md', sourceRoot: '../README.md', } }, diff --git a/site/src/app/layout.tsx b/site/src/app/layout.tsx index 85c7ab2c..63e9d8a2 100644 --- a/site/src/app/layout.tsx +++ b/site/src/app/layout.tsx @@ -1,49 +1,28 @@ import type { Metadata } from "next"; -import { Inter } from "next/font/google"; import { Analytics } from '@vercel/analytics/react'; +import { Inter } from "next/font/google"; import { Header, Footer, RobinProvider, KeylinkToContent } from 'robindoc'; import { Logo } from "../components/ui/logo"; import "robindoc/lib/styles.css"; import "./globals.css"; -import { Theme } from "robindoc/lib/core/types/theme"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { metadataBase: new URL('https://robindoc.com'), - title: "RobinDoc", - description: "RobinDoc is a framework for automatically creating documentation websites based on markdown files. Write the documentation however you want, Robindoc will build it on top. Fast, simple, easy", + title: "Robindoc", + description: "Robindoc is a framework for automatically creating documentation websites based on markdown files. Write the documentation however you want, Robindoc will build it on top. Fast, simple, easy", openGraph: { images: ['/preview.jpg'], } }; -const robinTheme: Theme = {} - const RootLayout: React.FC = ({ children }) => ( - +
=> { - const pages = await getPages(); - pages.push(''); + const staticParams = await getStaticParams(); + staticParams.push({ segments: [] }); - return pages.map(page => ({ - url: `https://robindoc.com${page}`, + return staticParams.map(({ segments }) => ({ + url: `https://robindoc.com/${segments.join('/')}/`, lastModified: new Date(), changeFrequency: 'daily', priority: 0.7, diff --git a/site/src/components/sections/showcases/index.tsx b/site/src/components/sections/showcases/index.tsx index 24fb8ec5..34b0ab33 100644 --- a/site/src/components/sections/showcases/index.tsx +++ b/site/src/components/sections/showcases/index.tsx @@ -7,7 +7,7 @@ import './showcases.scss'; const Showcases = () => (

- Tools chosen RobinDoc for their documentation + Tools chosen Robindoc for their documentation