Skip to content

Commit d8f90c0

Browse files
dakshesh14AntoLC
authored andcommitted
✨(frontend) add pdf blocks to the editor
Added pdf block in the editor. Signed-off-by: dakshesh14 <65905942+dakshesh14@users.noreply.github.com>
1 parent 1fdf70b commit d8f90c0

File tree

10 files changed

+143
-2
lines changed

10 files changed

+143
-2
lines changed

.github/workflows/impress.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ jobs:
7979
--check-filenames \
8080
--ignore-words-list "Dokument,afterAll,excpt,statics" \
8181
--skip "./git/" \
82+
--skip "**/*.pdf" \
8283
--skip "**/*.po" \
8384
--skip "**/*.pot" \
8485
--skip "**/*.json" \

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- ✨(frontend) add pdf block to the editor #1293
13+
1014
### Changed
1115

1216
- ♻️(frontend) replace Arial font-family with token font #1411
4.16 KB
Binary file not shown.

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,4 +840,38 @@ test.describe('Doc Editor', () => {
840840
).toBeInViewport();
841841
await expect(editor.getByText('Hello Child 14')).not.toBeInViewport();
842842
});
843+
844+
test('it embeds PDF', async ({ page, browserName }) => {
845+
await createDoc(page, 'doc-toolbar', browserName, 1);
846+
847+
await openSuggestionMenu({ page });
848+
await page.getByText('Embed a PDF file').click();
849+
850+
const pdfBlock = page.locator('div[data-content-type="pdf"]').first();
851+
852+
await expect(pdfBlock).toBeVisible();
853+
854+
await page.getByText('Add PDF').click();
855+
const fileChooserPromise = page.waitForEvent('filechooser');
856+
await page.getByText('Upload file').click();
857+
const fileChooser = await fileChooserPromise;
858+
859+
console.log(path.join(__dirname, 'assets/test-pdf.pdf'));
860+
await fileChooser.setFiles(path.join(__dirname, 'assets/test-pdf.pdf'));
861+
862+
// Wait for the media-check to be processed
863+
await page.waitForTimeout(1000);
864+
865+
const pdfEmbed = page
866+
.locator('.--docs--editor-container embed.bn-visual-media')
867+
.first();
868+
869+
// Check src of pdf
870+
expect(await pdfEmbed.getAttribute('src')).toMatch(
871+
/http:\/\/localhost:8083\/media\/.*\/attachments\/.*.pdf/,
872+
);
873+
874+
await expect(pdfEmbed).toHaveAttribute('type', 'application/pdf');
875+
await expect(pdfEmbed).toHaveAttribute('role', 'presentation');
876+
});
843877
});

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
AccessibleImageBlock,
3838
CalloutBlock,
3939
DividerBlock,
40+
PdfBlock,
4041
} from './custom-blocks';
4142
import {
4243
InterlinkingLinkInlineContent,
@@ -54,6 +55,7 @@ const baseBlockNoteSchema = withPageBreak(
5455
callout: CalloutBlock,
5556
divider: DividerBlock,
5657
image: AccessibleImageBlock,
58+
pdf: PdfBlock,
5759
},
5860
inlineContentSpecs: {
5961
...defaultInlineContentSpecs,

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import {
1919
getCalloutReactSlashMenuItems,
2020
getDividerReactSlashMenuItems,
21+
getPdfReactSlashMenuItems,
2122
} from './custom-blocks';
2223
import { useGetInterlinkingMenuItems } from './custom-inline-content';
2324
import XLMultiColumn from './xl-multi-column';
@@ -32,7 +33,10 @@ export const BlockNoteSuggestionMenu = () => {
3233
DocsStyleSchema
3334
>();
3435
const { t } = useTranslation();
35-
const basicBlocksName = useDictionary().slash_menu.page_break.group;
36+
const dictionaryDate = useDictionary();
37+
const basicBlocksName = dictionaryDate.slash_menu.page_break.group;
38+
const fileBlocksName = dictionaryDate.slash_menu.file.group;
39+
3640
const getInterlinkingMenuItems = useGetInterlinkingMenuItems();
3741

3842
const getSlashMenuItems = useMemo(() => {
@@ -56,11 +60,12 @@ export const BlockNoteSuggestionMenu = () => {
5660
getMultiColumnSlashMenuItems?.(editor) || [],
5761
getPageBreakReactSlashMenuItems(editor),
5862
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
63+
getPdfReactSlashMenuItems(editor, t, fileBlocksName),
5964
),
6065
query,
6166
),
6267
);
63-
}, [basicBlocksName, editor, getInterlinkingMenuItems, t]);
68+
}, [basicBlocksName, editor, getInterlinkingMenuItems, t, fileBlocksName]);
6469

6570
return (
6671
<SuggestionMenuController
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-disable react-hooks/rules-of-hooks */
2+
import { insertOrUpdateBlock } from '@blocknote/core';
3+
import {
4+
AddFileButton,
5+
ResizableFileBlockWrapper,
6+
createReactBlockSpec,
7+
} from '@blocknote/react';
8+
import { TFunction } from 'i18next';
9+
import { useTranslation } from 'react-i18next';
10+
import { createGlobalStyle } from 'styled-components';
11+
12+
import { Box, Icon } from '@/components';
13+
14+
import { DocsBlockNoteEditor } from '../../types';
15+
16+
const PDFBlockStyle = createGlobalStyle`
17+
.bn-block-content[data-content-type="pdf"] {
18+
width: fit-content;
19+
}
20+
`;
21+
22+
type FileBlockEditor = Parameters<typeof AddFileButton>[0]['editor'];
23+
24+
export const PdfBlock = createReactBlockSpec(
25+
{
26+
type: 'pdf',
27+
content: 'none',
28+
propSchema: {
29+
name: { default: '' as const },
30+
url: { default: '' as const },
31+
caption: { default: '' as const },
32+
showPreview: { default: true },
33+
previewWidth: { default: undefined, type: 'number' },
34+
},
35+
isFileBlock: true,
36+
fileBlockAccept: ['application/pdf'],
37+
},
38+
{
39+
render: ({ editor, block, contentRef }) => {
40+
const { t } = useTranslation();
41+
const pdfUrl = block.props.url;
42+
43+
return (
44+
<Box ref={contentRef} className="bn-file-block-content-wrapper">
45+
<PDFBlockStyle />
46+
<ResizableFileBlockWrapper
47+
buttonIcon={<Icon iconName="upload" />}
48+
block={block}
49+
editor={editor as unknown as FileBlockEditor}
50+
buttonText={t('Add PDF')}
51+
>
52+
<Box
53+
className="bn-visual-media"
54+
role="presentation"
55+
as="embed"
56+
$width="100%"
57+
$height="450px"
58+
type="application/pdf"
59+
src={pdfUrl}
60+
contentEditable={false}
61+
draggable={false}
62+
onClick={() => editor.setTextCursorPosition(block)}
63+
/>
64+
</ResizableFileBlockWrapper>
65+
</Box>
66+
);
67+
},
68+
},
69+
);
70+
71+
export const getPdfReactSlashMenuItems = (
72+
editor: DocsBlockNoteEditor,
73+
t: TFunction<'translation', undefined>,
74+
group: string,
75+
) => [
76+
{
77+
title: t('PDF'),
78+
onItemClick: () => {
79+
insertOrUpdateBlock(editor, { type: 'pdf' });
80+
},
81+
aliases: [t('pdf'), t('document'), t('embed'), t('file')],
82+
group,
83+
icon: <Icon iconName="picture_as_pdf" $size="18px" />,
84+
subtext: t('Embed a PDF file'),
85+
},
86+
];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './AccessibleImageBlock';
22
export * from './CalloutBlock';
33
export * from './DividerBlock';
4+
export * from './PdfBlock';

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export const docxDocsSchemaMappings: DocsExporterDocx['mappings'] = {
1616
...docxDefaultSchemaMappings.blockMapping,
1717
callout: blockMappingCalloutDocx,
1818
divider: blockMappingDividerDocx,
19+
// We're using the file block mapping for PDF blocks
20+
// The types don't match exactly but the implementation is compatible
21+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
22+
pdf: docxDefaultSchemaMappings.blockMapping.file as any,
1923
quote: blockMappingQuoteDocx,
2024
image: blockMappingImageDocx,
2125
},

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export const pdfDocsSchemaMappings: DocsExporterPDF['mappings'] = {
2323
divider: blockMappingDividerPDF,
2424
quote: blockMappingQuotePDF,
2525
table: blockMappingTablePDF,
26+
// We're using the file block mapping for PDF blocks
27+
// The types don't match exactly but the implementation is compatible
28+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
29+
pdf: pdfDefaultSchemaMappings.blockMapping.file as any,
2630
},
2731
inlineContentMapping: {
2832
...pdfDefaultSchemaMappings.inlineContentMapping,

0 commit comments

Comments
 (0)