Skip to content

Commit a15cf70

Browse files
committed
✨(frontend) interlinking export
Create interlinking link mapping for docx and pdf export.
1 parent da82ad3 commit a15cf70

File tree

9 files changed

+133
-6
lines changed

9 files changed

+133
-6
lines changed

src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,72 @@ test.describe('Doc Export', () => {
346346
const pdfData = await pdf(pdfBuffer);
347347
expect(pdfData.text).toContain('Hello World');
348348
});
349+
350+
test('it exports the doc with interlinking', async ({
351+
page,
352+
browserName,
353+
}) => {
354+
const [randomDoc] = await createDoc(
355+
page,
356+
'export-interlinking',
357+
browserName,
358+
1,
359+
);
360+
361+
await verifyDocName(page, randomDoc);
362+
363+
const [docChild] = await createDoc(
364+
page,
365+
'export-interlink-child',
366+
browserName,
367+
1,
368+
true,
369+
);
370+
371+
await verifyDocName(page, docChild);
372+
373+
await page.locator('.bn-block-outer').last().fill('/');
374+
await page.getByText('Link to a page').first().click();
375+
376+
await page
377+
.locator(
378+
"span[data-inline-content-type='interlinkingSearchInline'] input",
379+
)
380+
.fill('interlink-child');
381+
382+
await page
383+
.locator('.quick-search-container')
384+
.getByText('interlink-child')
385+
.click();
386+
387+
const interlink = page.getByRole('link', {
388+
name: 'interlink-child',
389+
});
390+
391+
await expect(interlink).toBeVisible();
392+
393+
const downloadPromise = page.waitForEvent('download', (download) => {
394+
return download.suggestedFilename().includes(`${docChild}.pdf`);
395+
});
396+
397+
await page
398+
.getByRole('button', {
399+
name: 'download',
400+
})
401+
.click();
402+
403+
void page
404+
.getByRole('button', {
405+
name: 'Download',
406+
})
407+
.click();
408+
409+
const download = await downloadPromise;
410+
expect(download.suggestedFilename()).toBe(`${docChild}.pdf`);
411+
412+
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
413+
const pdfData = await pdf(pdfBuffer);
414+
415+
expect(pdfData.text).toContain('interlink-child'); // This is the pdf text
416+
});
349417
});
338 Bytes
Loading

src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/paragraphPDF.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const blockMappingParagraphPDF: DocsExporterPDF['mappings']['blockMapping
1010
*/
1111
if (Array.isArray(block.content)) {
1212
block.content.forEach((content) => {
13-
if (content.type === 'text' && !content.text) {
13+
if (content.type === 'text' && 'text' in content && !content.text) {
1414
content.text = ' ';
1515
}
1616
});

src/frontend/apps/impress/src/features/docs/doc-export/blocks-mapping/quoteDocx.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ export const blockMappingQuoteDocx: DocsExporterDocx['mappings']['blockMapping']
88
if (Array.isArray(block.content)) {
99
block.content.forEach((content) => {
1010
if (content.type === 'text') {
11-
content.styles = {
12-
...content.styles,
13-
italic: true,
14-
textColor: 'gray',
15-
};
11+
if (
12+
'styles' in content &&
13+
typeof content.styles === 'object' &&
14+
content.styles !== null
15+
) {
16+
content.styles = {
17+
...content.styles,
18+
italic: true,
19+
textColor: 'gray',
20+
};
21+
}
1622
}
1723
});
1824
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './interlinkingLinkPDF';
2+
export * from './interlinkingLinkDocx';
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ExternalHyperlink, TextRun } from 'docx';
2+
3+
import { DocsExporterDocx } from '../types';
4+
5+
export const inlineContentMappingInterlinkingLinkDocx: DocsExporterDocx['mappings']['inlineContentMapping']['interlinkingLinkInline'] =
6+
(inline) => {
7+
return new ExternalHyperlink({
8+
children: [
9+
new TextRun({
10+
text: `📄${inline.props.title}`,
11+
bold: true,
12+
}),
13+
],
14+
link: window.location.origin + inline.props.url,
15+
});
16+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* eslint-disable jsx-a11y/alt-text */
2+
import { Image, Link } from '@react-pdf/renderer';
3+
4+
import DocSelectedIcon from '../assets/doc-selected.png';
5+
import { DocsExporterPDF } from '../types';
6+
7+
export const inlineContentMappingInterlinkingLinkPDF: DocsExporterPDF['mappings']['inlineContentMapping']['interlinkingLinkInline'] =
8+
(inline) => {
9+
return (
10+
<Link
11+
src={window.location.origin + inline.props.url}
12+
style={{
13+
textDecoration: 'none',
14+
color: 'black',
15+
}}
16+
>
17+
{' '}
18+
<Image src={DocSelectedIcon.src} />
19+
{inline.props.title}{' '}
20+
</Link>
21+
);
22+
};

src/frontend/apps/impress/src/features/docs/doc-export/mappingDocx.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { docxDefaultSchemaMappings } from '@blocknote/xl-docx-exporter';
2+
import { Paragraph } from 'docx';
23

34
import {
45
blockMappingCalloutDocx,
56
blockMappingDividerDocx,
67
blockMappingImageDocx,
78
blockMappingQuoteDocx,
89
} from './blocks-mapping';
10+
import { inlineContentMappingInterlinkingLinkDocx } from './inline-content-mapping';
911
import { DocsExporterDocx } from './types';
1012

1113
export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = {
@@ -17,4 +19,9 @@ export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = {
1719
quote: blockMappingQuoteDocx,
1820
image: blockMappingImageDocx,
1921
},
22+
inlineContentMapping: {
23+
...docxDefaultSchemaMappings.inlineContentMapping,
24+
interlinkingSearchInline: () => new Paragraph(''),
25+
interlinkingLinkInline: inlineContentMappingInterlinkingLinkDocx,
26+
},
2027
};

src/frontend/apps/impress/src/features/docs/doc-export/mappingPDF.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
blockMappingQuotePDF,
1010
blockMappingTablePDF,
1111
} from './blocks-mapping';
12+
import { inlineContentMappingInterlinkingLinkPDF } from './inline-content-mapping';
1213
import { DocsExporterPDF } from './types';
1314

1415
export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = {
@@ -23,4 +24,9 @@ export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = {
2324
quote: blockMappingQuotePDF,
2425
table: blockMappingTablePDF,
2526
},
27+
inlineContentMapping: {
28+
...pdfDefaultSchemaMappings.inlineContentMapping,
29+
interlinkingSearchInline: () => <></>,
30+
interlinkingLinkInline: inlineContentMappingInterlinkingLinkPDF,
31+
},
2632
};

0 commit comments

Comments
 (0)