From 85af5fd4e264c1332dc21eaf96f9489ee617a8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Fri, 3 Nov 2023 16:16:00 -0400 Subject: [PATCH] Start PDF html generation --- src/app/[spaceId]/.gitbook/pdf/page.tsx | 112 ++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/app/[spaceId]/.gitbook/pdf/page.tsx diff --git a/src/app/[spaceId]/.gitbook/pdf/page.tsx b/src/app/[spaceId]/.gitbook/pdf/page.tsx new file mode 100644 index 000000000..d67080f9f --- /dev/null +++ b/src/app/[spaceId]/.gitbook/pdf/page.tsx @@ -0,0 +1,112 @@ +import * as React from 'react'; + +import { api } from '@/lib/api'; +import { resolvePageId } from '@/lib/pages'; +import { DocumentView } from '@/components/DocumentView'; + +import { SpaceParams } from '../../fetch'; +import { Revision, RevisionPageDocument, RevisionPageGroup, Space } from '@gitbook/api'; +import { notFound } from 'next/navigation'; + +interface PDFSearchParams { + /** Page to export. If none is passed, all pages are exported. */ + page?: string; + /** If true, only the `page` is exported, and not its descendant */ + only?: boolean; +} + + +/** + * Render a space as a standalone HTML page without interactive elements. + * The HTML can be converted to PDF. + */ +export default async function PDFHTMLOutput(props: { params: SpaceParams; searchParams: PDFSearchParams }) { + const { params, searchParams } = props; + const { spaceId } = params; + + const [{ data: space }, { data: revision }] = await Promise.all([ + api().spaces.getSpaceById(spaceId), + api().spaces.getCurrentRevision(spaceId), + ]); + + const pages = selectPages(revision, searchParams).slice(0, 4); // TODO: remove slice + + return ( + <> + {pages.map(({ page, depth }) => ( + page.type === 'group' ? : + ))} + + ) +} + +async function PDFPageGroup(props: { + space: Space; + revision: Revision; + page: RevisionPageGroup; +}) { + const { page } = props; + + return ( +
+

{page.title}

+
+ ) +} + +async function PDFPageDocument(props: { + space: Space; + revision: Revision; + page: RevisionPageDocument; +}) { + const { space, revision, page } = props; + + const { + data: { document }, + } = await api().spaces.getPageInRevisionById(space.id, revision.id, page.id); + + return ( +
+

{page.title}

+ +
+ ) +} + +type FlatPageEntry = { page: RevisionPageDocument | RevisionPageGroup; depth: number }; + +/** + * Compute the ordered flat set of pages to render. + */ +function selectPages(revision: Revision, params: PDFSearchParams): FlatPageEntry[] { + const flattenPage = (page: RevisionPageDocument | RevisionPageGroup, depth: number): FlatPageEntry[] => { + return [ + { page, depth }, + ...page.pages.flatMap((child) => child.type === 'link' ? [] : flattenPage(child, depth + 1)), + ]; + } + + if (params.page) { + const found = resolvePageId(revision, params.page); + if (!found || found.page.type === 'link') { + notFound(); + } + + if (!params.only) { + return [{ page: found.page, depth: 0 }]; + } + + return flattenPage(found.page, 0); + } + + return revision.pages.flatMap((page) => page.type === 'link' ? [] : flattenPage(page, 0)); +} +