Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨(frontend) add pdf block to the editor #795

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to
## Changed

- ♻️(frontend) Integrate UI kit #783
- ✨(frontend) add pdf block to the editor #348

## [2.6.0] - 2025-03-21

Expand Down
3 changes: 3 additions & 0 deletions docker/files/etc/nginx/conf.d/default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ server {
proxy_pass http://minio:9000/impress-media-storage/;
proxy_set_header Host minio:9000;

proxy_hide_header Content-Disposition;
add_header Content-Disposition "inline";

add_header Content-Security-Policy "default-src 'none'" always;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ import { randomColor } from '../utils';

import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
import { DividerBlock, QuoteBlock } from './custom-blocks';
import { DividerBlock, PDFBlock, QuoteBlock } from './custom-blocks';

export const blockNoteSchema = withPageBreak(
BlockNoteSchema.create({
blockSpecs: {
...defaultBlockSpecs,
divider: DividerBlock,
quote: QuoteBlock,
pdf: PDFBlock,
},
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import { DocsBlockSchema } from '../types';

import {
getDividerReactSlashMenuItems,
getPdfSlackMenuItems,
getQuoteReactSlashMenuItems,
} from './custom-blocks';

export const BlockNoteSuggestionMenu = () => {
const editor = useBlockNoteEditor<DocsBlockSchema>();
const { t } = useTranslation();
const basicBlocksName = useDictionary().slash_menu.page_break.group;
const dictionaryDate = useDictionary();
const basicBlocksName = dictionaryDate.slash_menu.page_break.group;
const fileBlocksName = dictionaryDate.slash_menu.file.group;

const getSlashMenuItems = useMemo(() => {
return async (query: string) =>
Expand All @@ -30,11 +33,12 @@ export const BlockNoteSuggestionMenu = () => {
getPageBreakReactSlashMenuItems(editor),
getQuoteReactSlashMenuItems(editor, t, basicBlocksName),
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
getPdfSlackMenuItems(editor, t, fileBlocksName),
),
query,
),
);
}, [basicBlocksName, editor, t]);
}, [basicBlocksName, fileBlocksName, editor, t]);

return (
<SuggestionMenuController
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import {
FileBlockConfig,
InlineContentSchema,
StyleSchema,
insertOrUpdateBlock,
} from '@blocknote/core';
import {
AddFileButton,
FileBlockWrapper,
ReactCustomBlockRenderProps,
createReactBlockSpec,
} from '@blocknote/react';
import { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next';

import { Text } from '@/components';

import { useCheckEmbedCompatibility } from '../../hook/useCheckEmbedCompatibility';
import { DocsBlockNoteEditor } from '../../types';

export const PDFPreview = (
props: Omit<
ReactCustomBlockRenderProps<
FileBlockConfig,
InlineContentSchema,
StyleSchema
>,
'contentRef'
>,
) => {
const { t } = useTranslation();
const { isCompatible } = useCheckEmbedCompatibility();

const pdfUrl = props.block.props.url;

return (
<>
{isCompatible ? (
<embed
src={pdfUrl}
type="application/pdf"
width="100%"
height="500px"
contentEditable={false}
draggable={false}
onClick={() => props.editor.setTextCursorPosition(props.block)}
aria-label={props.block.props.name}
/>
) : (
<p>
{t('Your browser does not support PDFs.')}{' '}
<a href={pdfUrl}>{t('Download the pdf instead.')}</a>
</p>
)}
</>
);
};

export const PDFBlock = createReactBlockSpec(
{
type: 'pdf',
propSchema: {
name: {
default: '' as const,
},
url: {
default: '' as const,
},
caption: {
default: '' as const,
},
showPreview: {
default: true,
},
previewWidth: {
default: 512,
},
},
content: 'none',
isFileBlock: true,
} as const as FileBlockConfig,
{
render: (props) => (
<div ref={props.contentRef} className="bn-file-block-content-wrapper">
{props.block.props.url === '' ? (
<AddFileButton
{...props}
editor={props.editor}
buttonText="Add PDF"
buttonIcon={
<Text $isMaterialIcon $size="18px">
upload
</Text>
}
/>
) : (
<FileBlockWrapper block={props.block} editor={props.editor}>
<PDFPreview block={props.block} editor={props.editor} />
</FileBlockWrapper>
)}
</div>
),
},
);

export const getPdfSlackMenuItems = (
editor: DocsBlockNoteEditor,
t: TFunction<'translation', undefined>,
group: string,
) => [
{
title: t('PDF'),
onItemClick: () => {
insertOrUpdateBlock(editor, {
type: 'pdf',
});
},
aliases: ['pdf', 'document', 'embed', 'file'],
group,
icon: (
<Text $isMaterialIcon $size="18px">
upload
</Text>
),
subtext: t('Embed a pdf file'),
},
];
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './DividerBlock';
export * from './QuoteBlock';
export * from './PdfBlock';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useEffect, useState } from 'react';

export const useCheckEmbedCompatibility = () => {
const [isCompatible, setIsCompatible] = useState(true);

useEffect(() => {
const embedElement = document.createElement('embed');

setIsCompatible(
embedElement instanceof HTMLObjectElement ||
embedElement instanceof HTMLEmbedElement,
);
}, []);

return { isCompatible } as const;
};
15 changes: 12 additions & 3 deletions src/frontend/apps/impress/src/i18n/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,10 @@
"You do not have permission to view users sharing this document or modify link settings.": "Ihnen fehlt die Berechtigung, die das Dokument teilenden Benutzer einzusehen oder die Linkeinstellungen zu ändern.",
"Your current document will revert to this version.": "Ihr aktuelles Dokument wird auf diese Version zurückgesetzt.",
"Your {{format}} was downloaded succesfully": "Ihr {{format}} wurde erfolgreich heruntergeladen",
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "sie haben dem Website-Manager einen Mangel an Barrierefreiheit gemeldet, der Ihnen den Zugriff auf Inhalte oder einen der Dienste des Portals verwehrt, und Sie haben keine zufriedenstellende Antwort erhalten."
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "sie haben dem Website-Manager einen Mangel an Barrierefreiheit gemeldet, der Ihnen den Zugriff auf Inhalte oder einen der Dienste des Portals verwehrt, und Sie haben keine zufriedenstellende Antwort erhalten.",
"Embed a pdf file": "Eine PDF-Datei einbetten",
"Your browser does not support PDFs.": "Ihr Browser unterstützt keine PDFs.",
"Download the pdf instead.": "Laden Sie stattdessen die PDF herunter."
}
},
"en": {
Expand Down Expand Up @@ -438,7 +441,10 @@
"home-content-open-source-part1": "Docs est construit sur <2>Django Rest Framework</2> et <6>Next.js</6>. Nous utilisons également <9>Yjs</9> et <13>BlockNote.js</13>, deux projets que nous sommes fiers de sponsoriser.",
"home-content-open-source-part2": "Vous pouvez facilement auto-héberger Docs (consultez notre <2>documentation</2> d'installation).<br/>Docs utilise une <7>licence</7> (MIT) adaptée à l'innovation et aux entreprises.<br/>Les contributions sont les bienvenues (consultez notre feuille de route <13>ici</13>).",
"home-content-open-source-part3": "Docs est le résultat d'un effort conjoint mené par les gouvernements français 🇫🇷🥖 <1>(DINUM)</1> et allemand 🇩🇪🥨 <5>(ZenDiS)</5>.",
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "vous avez signalé au responsable du site internet un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un des services du portail et vous n'avez pas obtenu de réponse satisfaisante."
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "vous avez signalé au responsable du site internet un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un des services du portail et vous n'avez pas obtenu de réponse satisfaisante.",
"Embed a pdf file": "Intégrer un fichier PDF",
"Your browser does not support PDFs.": "Votre navigateur ne prend pas en charge les fichiers PDF.",
"Download the pdf instead.": "Téléchargez plutôt le fichier PDF."
}
},
"nl": {
Expand Down Expand Up @@ -664,7 +670,10 @@
"home-content-open-source-part1": "home-content-open-source-part1",
"home-content-open-source-part2": "home-content-open-source-part2",
"home-content-open-source-part3": "home-content-open-source-part3",
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "u heeft aan de websitebeheerder gerapporteerd dat u geen toegang heeft tot de inhoud of een van de diensten van het portaal, en u hebt geen bevredigend antwoord ontvangen."
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "u heeft aan de websitebeheerder gerapporteerd dat u geen toegang heeft tot de inhoud of een van de diensten van het portaal, en u hebt geen bevredigend antwoord ontvangen.",
"Embed a pdf file": "Een PDF-bestand insluiten",
"Your browser does not support PDFs.": "Uw browser ondersteunt geen PDF's.",
"Download the pdf instead.": "Download de PDF in plaats daarvan."
}
},
"tr": { "translation": {} }
Expand Down