diff --git a/CHANGELOG.md b/CHANGELOG.md index 37be2853..f6f28482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +## Added + +- ✨(frontend) Custom block divider with export #698 + ## Changed - 🧑‍💻(frontend) change literal section open source #702 diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts index 70acd37e..c7f799aa 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts @@ -257,4 +257,47 @@ test.describe('Doc Export', () => { expect(pdfData.text).toContain('Hello World'); // This is the pdf text }); + + /** + * We cannot assert the line break is visible in the pdf but we can assert the + * line break is visible in the editor and that the pdf is generated. + */ + test('it exports the doc with divider', async ({ page, browserName }) => { + const [randomDoc] = await createDoc(page, 'export-divider', browserName, 1); + + const downloadPromise = page.waitForEvent('download', (download) => { + return download.suggestedFilename().includes(`${randomDoc}.pdf`); + }); + + const editor = page.locator('.ProseMirror'); + await editor.click(); + await editor.fill('Hello World'); + + // Trigger slash menu to show menu + await editor.locator('.bn-block-outer').last().fill('/'); + await page.getByText('Add a horizontal line').click(); + + await expect( + editor.locator('.bn-block-content[data-content-type="divider"]'), + ).toBeVisible(); + + await page + .getByRole('button', { + name: 'download', + }) + .click(); + + await page + .getByRole('button', { + name: 'Download', + }) + .click(); + + const download = await downloadPromise; + expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`); + + const pdfBuffer = await cs.toBuffer(await download.createReadStream()); + const pdfData = await pdf(pdfBuffer); + expect(pdfData.text).toContain('Hello World'); + }); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx new file mode 100644 index 00000000..49df88f1 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerDocx.tsx @@ -0,0 +1,24 @@ +import { Paragraph } from 'docx'; + +import { useCunninghamTheme } from '@/cunningham'; + +import { DocsExporterDocx } from '../types'; + +export const blockMappingDividerDocx: DocsExporterDocx['mappings']['blockMapping']['divider'] = + () => { + const { colorsTokens } = useCunninghamTheme.getState(); + + return new Paragraph({ + spacing: { + before: 200, + }, + border: { + top: { + color: colorsTokens()['greyscale-300'], + size: 1, + style: 'single', + space: 1, + }, + }, + }); + }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx new file mode 100644 index 00000000..844185d1 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/dividerPDF.tsx @@ -0,0 +1,20 @@ +import { Text } from '@react-pdf/renderer'; + +import { useCunninghamTheme } from '@/cunningham'; + +import { DocsExporterPDF } from '../types'; + +export const blockMappingDividerPDF: DocsExporterPDF['mappings']['blockMapping']['divider'] = + () => { + const { colorsTokens } = useCunninghamTheme.getState(); + + return ( + + ); + }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/index.ts b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/index.ts index a4fd91a2..38d4ba84 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/index.ts @@ -1,3 +1,5 @@ +export * from './dividerDocx'; +export * from './dividerPDF'; export * from './headingPDF'; export * from './paragraphPDF'; export * from './quoteDocx'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx index c34f28fb..79bb1150 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx @@ -1,12 +1,16 @@ import { docxDefaultSchemaMappings } from '@blocknote/xl-docx-exporter'; -import { blockMappingQuoteDocx } from './blocks-mapping/'; +import { + blockMappingDividerDocx, + blockMappingQuoteDocx, +} from './blocks-mapping/'; import { DocsExporterDocx } from './types'; export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = { ...docxDefaultSchemaMappings, blockMapping: { ...docxDefaultSchemaMappings.blockMapping, + divider: blockMappingDividerDocx, quote: blockMappingQuoteDocx, }, }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx index d4ca9364..de16a6c3 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx @@ -1,6 +1,7 @@ import { pdfDefaultSchemaMappings } from '@blocknote/xl-pdf-exporter'; import { + blockMappingDividerPDF, blockMappingHeadingPDF, blockMappingParagraphPDF, blockMappingQuotePDF, @@ -14,6 +15,7 @@ export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = { ...pdfDefaultSchemaMappings.blockMapping, heading: blockMappingHeadingPDF, paragraph: blockMappingParagraphPDF, + divider: blockMappingDividerPDF, quote: blockMappingQuotePDF, table: blockMappingTablePDF, },