-
+ <>
+ {searchParams.back !== 'false' ? (
+
+ ) : null}
+
+
+
+
+
+ {searchParams.only ? null :
}
{pages.map(({ page, depth }) =>
page.type === 'group' ? (
@@ -86,9 +148,7 @@ export default async function PDFHTMLOutput(props: {
),
)}
-
-
-
+ >
);
}
@@ -96,9 +156,11 @@ async function SpaceIntro(props: { space: Space }) {
const { space } = props;
return (
-
-
{page.title}
+
+ {page.title}
+ {page.description ? (
+ {page.description}
+ ) : null}
+
{document ? (
) : null}
+
+ );
+}
+
+function PrintPage(
+ props: PolymorphicComponentProp<
+ 'div',
+ {
+ isFirst?: boolean;
+ }
+ >,
+) {
+ const { children, isFirst, className, ...rest } = props;
+
+ return (
+
+ {children}
);
}
@@ -157,7 +258,10 @@ type FlatPageEntry = { page: RevisionPageDocument | RevisionPageGroup; depth: nu
/**
* Compute the ordered flat set of pages to render.
*/
-function selectPages(rootPages: Revision['pages'], params: PDFSearchParams): FlatPageEntry[] {
+function selectPages(
+ rootPages: Revision['pages'],
+ params: PDFSearchParams,
+): { pages: FlatPageEntry[]; total: number } {
const flattenPage = (
page: RevisionPageDocument | RevisionPageGroup,
depth: number,
@@ -170,6 +274,14 @@ function selectPages(rootPages: Revision['pages'], params: PDFSearchParams): Fla
];
};
+ const limitTo = (entries: FlatPageEntry[]) => {
+ return {
+ // Apply a soft-limit, the limit can be controlled by the URL to allow testing
+ pages: entries.slice(0, params.limit ?? 100),
+ total: entries.length,
+ };
+ };
+
if (params.page) {
const found = resolvePageId(rootPages, params.page);
if (!found) {
@@ -177,11 +289,14 @@ function selectPages(rootPages: Revision['pages'], params: PDFSearchParams): Fla
}
if (!params.only) {
- return [{ page: found.page, depth: 0 }];
+ return limitTo([{ page: found.page, depth: 0 }]);
}
- return flattenPage(found.page, 0);
+ return limitTo(flattenPage(found.page, 0));
}
- return rootPages.flatMap((page) => (page.type === 'link' ? [] : flattenPage(page, 0)));
+ const allPages = rootPages.flatMap((page) =>
+ page.type === 'link' ? [] : flattenPage(page, 0),
+ );
+ return limitTo(allPages);
}
diff --git a/src/app/[spaceId]/~gitbook/pdf/params.ts b/src/app/[spaceId]/~gitbook/pdf/params.ts
new file mode 100644
index 000000000..15ebaca83
--- /dev/null
+++ b/src/app/[spaceId]/~gitbook/pdf/params.ts
@@ -0,0 +1,31 @@
+export 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;
+ /** Limit the number of pages */
+ limit?: number;
+ /** URL to redirect back to */
+ back?: string;
+}
+
+/**
+ * Generate a search params part of the URL for the PDF export.
+ */
+export function getPDFParams(params?: PDFSearchParams): string {
+ const searchParams = new URLSearchParams();
+ if (params?.page) {
+ searchParams.set('page', params.page);
+ }
+ if (params?.only) {
+ searchParams.set('only', 'yes');
+ }
+ if (params?.limit) {
+ searchParams.set('limit', String(params.limit));
+ }
+ if (params?.back) {
+ searchParams.set('back', String(params.back));
+ }
+
+ return searchParams.toString();
+}
diff --git a/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx b/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx
index 721318880..4643a76f7 100644
--- a/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx
+++ b/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx
@@ -41,7 +41,7 @@ export function CopyCodeButton(props: { codeId: string; style: ClassValue }) {
};
return (
-
);
diff --git a/src/components/PageAside/ScrollSectionsList.tsx b/src/components/PageAside/ScrollSectionsList.tsx
index c5c84af89..f5fa578f4 100644
--- a/src/components/PageAside/ScrollSectionsList.tsx
+++ b/src/components/PageAside/ScrollSectionsList.tsx
@@ -3,7 +3,7 @@
import Link from 'next/link';
import React from 'react';
-import { IconChevronRight } from '@/components/icons/IconChevronRight';
+import { useScrollActiveId } from '@/components/hooks';
import { DocumentSection } from '@/lib/document';
import { tcls } from '@/lib/tailwind';
@@ -16,64 +16,18 @@ const SECTION_INTERSECTING_THRESHOLD = 0.9;
export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
const { sections } = props;
- const [activeId, setActiveId] = React.useState