From f6ced2de80b342301ba52330102c7ee3a1b92f4e Mon Sep 17 00:00:00 2001 From: pfdgithub Date: Fri, 14 Jun 2024 16:23:47 +0800 Subject: [PATCH] feat: support `tocTitle` and `disableCover` --- README.md | 2 ++ src/command.ts | 4 ++- src/core.ts | 13 ++++++--- src/utils.ts | 24 ++++++++++++----- tests/docusaurus.spec.ts | 8 ++++-- tests/utils_jsdom.spec.ts | 55 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 89 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b378efb9..0e7efefe 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ npx docs-to-pdf --initialDocURLs="https://docusaurus.io/docs/" --contentSelector | `--pdfMargin` | No | set margin around PDF file. Separate each margin **with comma and no space**. ex: `--pdfMargin="10,20,30,40"`. This sets margin `top: 10px, right: 20px, bottom: 30px, left: 40px` | | `--paperFormat` | No | pdf format ex: `--paperFormat="A3"`. Please check this link for available formats [Puppeteer document](https://pptr.dev/#?product=Puppeteer&version=v5.2.1&show=api-pagepdfoptions)| | `--disableTOC` | No | Optional toggle to show the table of contents or not | +| `--tocTitle` | No | Title for the table of contents. | +| `--disableCover` | No | Optional toggle to show the PDF cover or not. | | `--coverTitle` | No | Title for the PDF cover. | | `--coverImage` | No | `` Image for PDF cover (does not support SVG) | | `--coverSub` | No | Subtitle the for PDF cover. Add `
` tags for multiple lines. | diff --git a/src/command.ts b/src/command.ts index 004b2b2a..7332a87a 100644 --- a/src/command.ts +++ b/src/command.ts @@ -108,12 +108,14 @@ export function makeProgram() { ) .option('--pdfFormat ', '(DEPRECATED use paperFormat)') //TODO: Remove at next major version, replaced by paperFormat .option('--paperFormat ', 'pdf format ex: A3, A4...') + .option('--disableTOC', 'disable table of contents') + .option('--tocTitle ', 'title for table of contents') + .option('--disableCover', 'disable PDF cover') .option('--coverTitle <title>', 'title for PDF cover') .option( '--coverImage <src>', 'image for PDF cover. *.svg file not working!', ) - .option('--disableTOC', 'disable table of contents') .option('--coverSub <subtitle>', 'subtitle for PDF cover') .option( '--waitForRender <timeout>', diff --git a/src/core.ts b/src/core.ts index 80aec9ef..c8a9b707 100644 --- a/src/core.ts +++ b/src/core.ts @@ -22,9 +22,11 @@ export interface GeneratePDFOptions { excludeSelectors: Array<string>; cssStyle: string; puppeteerArgs: Array<string>; + disableTOC: boolean; + tocTitle: string; + disableCover: boolean; coverTitle: string; coverImage: string; - disableTOC: boolean; coverSub: string; waitForRender: number; headerTemplate: string; @@ -49,9 +51,11 @@ export async function generatePDF({ excludeSelectors, cssStyle, puppeteerArgs, + disableTOC, + tocTitle, + disableCover, coverTitle, coverImage, - disableTOC, coverSub, waitForRender, headerTemplate, @@ -152,7 +156,9 @@ export async function generatePDF({ ); // Generate Toc - const { modifiedContentHTML, tocHTML } = utils.generateToc(contentHTML); + const { modifiedContentHTML, tocHTML } = utils.generateToc(contentHTML, { + tocTitle, + }); // Restructuring the HTML of a document console.log(chalk.cyan('Restructuring the html of a document...')); @@ -166,6 +172,7 @@ export async function generatePDF({ tocHTML, modifiedContentHTML, disableTOC, + disableCover, baseUrl, ); diff --git a/src/utils.ts b/src/utils.ts index b2da1544..7a549143 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -140,7 +140,8 @@ export function concatHtml( cover: string, toc: string, content: string, - disable: boolean, + disableTOC: boolean, + disableCover: boolean, baseUrl: string, ) { // Clear the body content @@ -154,10 +155,12 @@ export function concatHtml( } // Add the cover HTML to the body - body.innerHTML += cover; + if (!disableCover) { + body.innerHTML += cover; + } // Add the table of contents HTML to the body if not disabled - if (!disable) { + if (!disableTOC) { body.innerHTML += toc; } @@ -246,7 +249,13 @@ export function generateCoverHtml( * @param maxLevel - The maximum header level to include in the TOC. Defaults to 3. * @returns An object containing the modified content HTML and the TOC HTML. */ -export function generateToc(contentHtml: string, maxLevel = 4) { +export function generateToc( + contentHtml: string, + options?: { maxLevel?: number; tocTitle?: string }, +) { + const maxLevel = options?.maxLevel ?? 4; + const tocTitle = options?.tocTitle; + const headers: Array<{ header: string; level: number; @@ -271,7 +280,7 @@ export function generateToc(contentHtml: string, maxLevel = 4) { return replaceHeader(matchedStr, headerId, maxLevel); } - const tocHTML = generateTocHtml(headers); + const tocHTML = generateTocHtml(headers, tocTitle); return { modifiedContentHTML, tocHTML }; } @@ -281,7 +290,8 @@ export function generateToc(contentHtml: string, maxLevel = 4) { * @param headers - An array of header objects containing level, id, and header properties. * @returns The HTML code for the table of contents. */ -export function generateTocHtml(headers: any[]) { +export function generateTocHtml(headers: any[], tocTitle?: string) { + const title = tocTitle ?? 'Table of contents:'; // Map the headers array to create a list item for each header with the appropriate indentation const toc = headers .map( @@ -294,7 +304,7 @@ export function generateTocHtml(headers: any[]) { // Return the HTML code for the table of contents return ` <div class="toc-page" style="page-break-after: always;"> - <h1 class="toc-header">Table of contents:</h1> + ${title ? `<h1 class="toc-header">${title}</h1>` : ''} ${toc} </div> `; diff --git a/tests/docusaurus.spec.ts b/tests/docusaurus.spec.ts index 001072bc..b9c01267 100644 --- a/tests/docusaurus.spec.ts +++ b/tests/docusaurus.spec.ts @@ -25,9 +25,11 @@ describe('generateDocusaurusPDF', () => { excludeSelectors: [], cssStyle: '', puppeteerArgs: [], + disableTOC: false, + tocTitle: 'Table of contents:', + disableCover: false, coverTitle: '', coverImage: '', - disableTOC: false, coverSub: '', waitForRender: 0, headerTemplate: '', @@ -232,9 +234,11 @@ describe('generateFromBuild', () => { excludeSelectors: [], cssStyle: '', puppeteerArgs: [], + disableTOC: false, + tocTitle: 'Table of contents:', + disableCover: false, coverTitle: '', coverImage: '', - disableTOC: false, coverSub: '', waitForRender: 0, headerTemplate: '', diff --git a/tests/utils_jsdom.spec.ts b/tests/utils_jsdom.spec.ts index e7cf645a..adba01c1 100644 --- a/tests/utils_jsdom.spec.ts +++ b/tests/utils_jsdom.spec.ts @@ -75,11 +75,20 @@ describe('concatHtml', () => { const cover = '<div class="cover">Cover</div>'; const toc = '<ul><li>TOC</li></ul>'; const content = '<div class="content">Content</div>'; - const disable = false; + const disableTOC = false; + const disableCover = false; + const baseUrl = ''; it('should concatenate the HTML elements correctly', () => { const baseUrl = 'http://example.com/'; - const result = concatHtml(cover, toc, content, disable, baseUrl); + const result = concatHtml( + cover, + toc, + content, + disableTOC, + disableCover, + baseUrl, + ); expect(result).toBe( `<base href="http://example.com/"><div class="cover">Cover</div><ul><li>TOC</li></ul><div class="content">Content</div>`, @@ -87,13 +96,51 @@ describe('concatHtml', () => { }); it('should not add base when no baseUrl given', () => { - const baseUrl = ''; - const result = concatHtml(cover, toc, content, disable, baseUrl); + const result = concatHtml( + cover, + toc, + content, + disableTOC, + disableCover, + baseUrl, + ); expect(result).toBe( `<div class="cover">Cover</div><ul><li>TOC</li></ul><div class="content">Content</div>`, ); }); + + it('should not add toc when disableTOC given', () => { + const disableTOC = true; + const result = concatHtml( + cover, + toc, + content, + disableTOC, + disableCover, + baseUrl, + ); + + expect(result).toBe( + `<div class="cover">Cover</div><div class="content">Content</div>`, + ); + }); + + it('should not add cover when disableCover given', () => { + const disableCover = true; + const result = concatHtml( + cover, + toc, + content, + disableTOC, + disableCover, + baseUrl, + ); + + expect(result).toBe( + `<ul><li>TOC</li></ul><div class="content">Content</div>`, + ); + }); }); describe('removeElementFromSelector', () => {