diff --git a/CHANGELOG.md b/CHANGELOG.md index a29f4cf81..3f555bc86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,14 @@ and this project adheres to ## [Unreleased] ## Added + - 📝(doc) Add security.md and codeofconduct.md #604 +## Fixed + +- 💄improve export spacings PDF #613 + + ## [2.1.0] - 2025-01-29 ## Added diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx index 19094b6c5..36dbe0ce1 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/types.tsx @@ -1,3 +1,5 @@ +import { BlockNoteEditor, BlockNoteSchema } from '@blocknote/core'; + export interface DocAttachment { file: string; } @@ -12,3 +14,19 @@ export type HeadingBlock = { level: number; }; }; + +export const blockNoteInstance = BlockNoteSchema.create(); +export type DocsBlockSchema = typeof blockNoteInstance.blockSchema; +export type DocsInlineContentSchema = + typeof blockNoteInstance.inlineContentSchema; +export type DocsStyleSchema = typeof blockNoteInstance.styleSchema; +export type DocsBlockNoteEditor = BlockNoteEditor< + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema +>; +export type DocsBlockNoteSchema = BlockNoteSchema< + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema +>; diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/ModalExport.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/ModalExport.tsx index 7d7f1657f..fddd7351f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/ModalExport.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/ModalExport.tsx @@ -2,10 +2,6 @@ import { DOCXExporter, docxDefaultSchemaMappings, } from '@blocknote/xl-docx-exporter'; -import { - PDFExporter, - pdfDefaultSchemaMappings, -} from '@blocknote/xl-pdf-exporter'; import { Button, Loader, @@ -25,6 +21,7 @@ import { useEditorStore } from '@/features/docs/doc-editor'; import { Doc } from '@/features/docs/doc-management'; import { TemplatesOrdering, useTemplates } from '../api/useTemplates'; +import { DocsPDFExporter } from '../libs/DocsPDFExporter'; import { downloadFile, exportResolveFileUrl } from '../utils'; enum DocDownloadFormat { @@ -91,19 +88,12 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => { let blobExport: Blob; if (format === DocDownloadFormat.PDF) { - const defaultExporter = new PDFExporter( - editor.schema, - pdfDefaultSchemaMappings, - ); + const defaultExporter = new DocsPDFExporter(editor.schema); + const exporter = new DocsPDFExporter(editor.schema, { + resolveFileUrl: async (url) => + exportResolveFileUrl(url, defaultExporter.options.resolveFileUrl), + }); - const exporter = new PDFExporter( - editor.schema, - pdfDefaultSchemaMappings, - { - resolveFileUrl: async (url) => - exportResolveFileUrl(url, defaultExporter.options.resolveFileUrl), - }, - ); const pdfDocument = await exporter.toReactPDFDocument(exportDocument); blobExport = await pdf(pdfDocument).toBlob(); } else { diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/libs/DocsPDFExporter.ts b/src/frontend/apps/impress/src/features/docs/doc-header/libs/DocsPDFExporter.ts new file mode 100644 index 000000000..a2be7ea98 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-header/libs/DocsPDFExporter.ts @@ -0,0 +1,87 @@ +import { Block, DefaultProps, ExporterOptions } from '@blocknote/core'; +import { + PDFExporter, + pdfDefaultSchemaMappings, +} from '@blocknote/xl-pdf-exporter'; +import { Font } from '@react-pdf/renderer'; + +import { + DocsBlockNoteSchema, + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema, +} from '@/features/docs/doc-editor'; + +type Options = ExporterOptions & { + emojiSource: false | ReturnType; +}; + +type DocsDefaultProps = DefaultProps & { + level?: number; +}; + +export class DocsPDFExporter extends PDFExporter< + DocsBlockSchema, + DocsStyleSchema, + DocsInlineContentSchema +> { + constructor( + protected readonly schemaMappings: DocsBlockNoteSchema, + options?: Partial, + ) { + super(schemaMappings, pdfDefaultSchemaMappings, options); + } + + /** + * Breaklines are not displayed in PDFs, by adding a space we ensure that the line is not ignored + * @param blocks + * @param nestingLevel + * @returns + */ + public transformBlocks( + blocks: Block[], // Or BlockFromConfig? + nestingLevel?: number, + ) { + blocks.forEach((block) => { + if (Array.isArray(block.content)) { + block.content.forEach((content) => { + if (content.type === 'text' && !content.text) { + content.text = ' '; + } + }); + + if (!block.content.length) { + block.content.push({ + styles: {}, + text: ' ', + type: 'text', + }); + } + } + }); + + return super.transformBlocks(blocks, nestingLevel); + } + + /** + * Override the method to add our custom styles + * @param props + * @returns + */ + public blocknoteDefaultPropsToReactPDFStyle( + props: Partial, + ) { + let styles = super.blocknoteDefaultPropsToReactPDFStyle(props); + + // Add margin to headings + if (props.level) { + styles = { + marginTop: 15, + marginBottom: 15, + ...styles, + }; + } + + return styles; + } +}