From 853fab53ab37567acc23d2f1c5bf8c8d0c4a573b Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Sat, 27 Jan 2024 16:04:20 +0530 Subject: [PATCH] feat: Added "Page size" option when exporting Super notes as PDF --- .../app/javascripts/Renderer/Renderer.ts | 2 +- .../Service/SuperConverterServiceInterface.ts | 10 +++ .../Domain/Syncable/UserPrefs/PrefDefaults.ts | 1 + .../src/Domain/Syncable/UserPrefs/PrefKey.ts | 2 + .../Components/NotesOptions/NotesOptions.tsx | 2 +- .../NotesOptions/SuperExportModal.tsx | 65 ++++++++++++++----- .../Lexical/Utils/PDFExport/PDFExport.tsx | 5 +- .../Lexical/Utils/PDFExport/PDFWorker.tsx | 8 ++- .../Tools/HeadlessSuperConverter.tsx | 7 +- .../src/javascripts/Utils/NoteExportUtils.ts | 6 ++ 10 files changed, 82 insertions(+), 26 deletions(-) diff --git a/packages/desktop/app/javascripts/Renderer/Renderer.ts b/packages/desktop/app/javascripts/Renderer/Renderer.ts index de7291c78..28db7df7f 100644 --- a/packages/desktop/app/javascripts/Renderer/Renderer.ts +++ b/packages/desktop/app/javascripts/Renderer/Renderer.ts @@ -128,7 +128,7 @@ async function configureWindow(remoteBridge: CrossProcessBridge) { /* Use custom title bar. Take the sn-titlebar-height off of the app content height so its not overflowing */ sheet.insertRule( - '[role="dialog"]:not(.challenge-modal) { height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; margin-top: var(--sn-desktop-titlebar-height); }', + '[role="dialog"]:not(.challenge-modal) { max-height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; margin-top: var(--sn-desktop-titlebar-height); }', sheet.cssRules.length, ) sheet.insertRule( diff --git a/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts b/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts index 6a8a52f84..8c1aa13c0 100644 --- a/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts +++ b/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts @@ -1,8 +1,18 @@ +import { FileItem, PrefKey, PrefValue } from '@standardnotes/models' + export interface SuperConverterServiceInterface { isValidSuperString(superString: string): boolean convertSuperStringToOtherFormat: ( superString: string, toFormat: 'txt' | 'md' | 'html' | 'json' | 'pdf', + config?: { + embedBehavior?: PrefValue[PrefKey.SuperNoteExportEmbedBehavior] + getFileItem?: (id: string) => FileItem | undefined + getFileBase64?: (id: string) => Promise + pdf?: { + pageSize?: PrefValue[PrefKey.SuperNoteExportPDFPageSize] + } + }, ) => Promise convertOtherFormatToSuperString: ( otherFormatString: string, diff --git a/packages/models/src/Domain/Syncable/UserPrefs/PrefDefaults.ts b/packages/models/src/Domain/Syncable/UserPrefs/PrefDefaults.ts index 8ddb2f57c..4c6b1d507 100644 --- a/packages/models/src/Domain/Syncable/UserPrefs/PrefDefaults.ts +++ b/packages/models/src/Domain/Syncable/UserPrefs/PrefDefaults.ts @@ -42,6 +42,7 @@ export const PrefDefaults = { [PrefKey.SuperNoteExportFormat]: 'json', [PrefKey.SuperNoteExportEmbedBehavior]: 'reference', [PrefKey.SuperNoteExportUseMDFrontmatter]: true, + [PrefKey.SuperNoteExportPDFPageSize]: 'A4', [PrefKey.SystemViewPreferences]: {}, [PrefKey.AuthenticatorNames]: '', [PrefKey.ComponentPreferences]: {}, diff --git a/packages/models/src/Domain/Syncable/UserPrefs/PrefKey.ts b/packages/models/src/Domain/Syncable/UserPrefs/PrefKey.ts index b6b1fd6f9..8fc7ef3b7 100644 --- a/packages/models/src/Domain/Syncable/UserPrefs/PrefKey.ts +++ b/packages/models/src/Domain/Syncable/UserPrefs/PrefKey.ts @@ -43,6 +43,7 @@ export enum PrefKey { SuperNoteExportFormat = 'superNoteExportFormat', SuperNoteExportEmbedBehavior = 'superNoteExportEmbedBehavior', SuperNoteExportUseMDFrontmatter = 'superNoteExportUseMDFrontmatter', + SuperNoteExportPDFPageSize = 'superNoteExportPDFPageSize', AuthenticatorNames = 'authenticatorNames', PaneGesturesEnabled = 'paneGesturesEnabled', ComponentPreferences = 'componentPreferences', @@ -90,6 +91,7 @@ export type PrefValue = { [PrefKey.SuperNoteExportFormat]: 'json' | 'md' | 'html' | 'pdf' [PrefKey.SuperNoteExportEmbedBehavior]: 'reference' | 'inline' | 'separate' [PrefKey.SuperNoteExportUseMDFrontmatter]: boolean + [PrefKey.SuperNoteExportPDFPageSize]: 'A3' | 'A4' | 'LETTER' | 'LEGAL' | 'TABLOID' [PrefKey.AuthenticatorNames]: string [PrefKey.PaneGesturesEnabled]: boolean [PrefKey.ComponentPreferences]: AllComponentPreferences diff --git a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx index 8bfeda783..ddd7ea37a 100644 --- a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx +++ b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx @@ -499,7 +499,7 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => { )} - + diff --git a/packages/web/src/javascripts/Components/NotesOptions/SuperExportModal.tsx b/packages/web/src/javascripts/Components/NotesOptions/SuperExportModal.tsx index 2357c8e94..4fa4570f0 100644 --- a/packages/web/src/javascripts/Components/NotesOptions/SuperExportModal.tsx +++ b/packages/web/src/javascripts/Components/NotesOptions/SuperExportModal.tsx @@ -6,6 +6,7 @@ import RadioButtonGroup from '../RadioButtonGroup/RadioButtonGroup' import { useEffect } from 'react' import Switch from '../Switch/Switch' import { noteHasEmbeddedFiles } from '@/Utils/NoteExportUtils' +import Dropdown from '../Dropdown/Dropdown' type Props = { notes: SNNote[] @@ -19,6 +20,7 @@ const SuperExportModal = ({ notes, exportNotes, close }: Props) => { const superNoteExportFormat = usePreference(PrefKey.SuperNoteExportFormat) const superNoteExportEmbedBehavior = usePreference(PrefKey.SuperNoteExportEmbedBehavior) const superNoteExportUseMDFrontmatter = usePreference(PrefKey.SuperNoteExportUseMDFrontmatter) + const superNoteExportPDFPageSize = usePreference(PrefKey.SuperNoteExportPDFPageSize) useEffect(() => { if (superNoteExportFormat === 'json' && superNoteExportEmbedBehavior === 'separate') { @@ -60,23 +62,25 @@ const SuperExportModal = ({ notes, exportNotes, close }: Props) => { ]} >
-
We detected your selection includes Super notes.
-
What format do you want to export them in?
- { - void application.setPreference( - PrefKey.SuperNoteExportFormat, - value as PrefValue[PrefKey.SuperNoteExportFormat], - ) - }} - /> +
+
Choose export format {notes.length > 1 ? 'for Super notes' : ''}
+ { + void application.setPreference( + PrefKey.SuperNoteExportFormat, + value as PrefValue[PrefKey.SuperNoteExportFormat], + ) + }} + /> +
{superNoteExportFormat === 'md' && (
Note that conversion to Markdown is not lossless. Some features like collapsible blocks and formatting like @@ -84,6 +88,33 @@ const SuperExportModal = ({ notes, exportNotes, close }: Props) => {
)}
+ {superNoteExportFormat === 'pdf' && ( +
+
Page size
+ { + void application.setPreference( + PrefKey.SuperNoteExportPDFPageSize, + value as PrefValue[PrefKey.SuperNoteExportPDFPageSize], + ) + }} + /> +
+ )} {superNoteExportFormat === 'md' && (
(new Worker(new URL('./PDFWorker.tsx', i /** * @returns The PDF as a base64 string */ -export function $generatePDFFromNodes(editor: LexicalEditor) { +export function $generatePDFFromNodes(editor: LexicalEditor, pageSize: PrefValue[PrefKey.SuperNoteExportPDFPageSize]) { return new Promise((resolve) => { editor.getEditorState().read(() => { const root = $getRoot() @@ -430,7 +431,7 @@ export function $generatePDFFromNodes(editor: LexicalEditor) { const pdfDataNodes = getPDFDataNodesFromLexicalNodes(nodes) - void PDFWorkerComlink.renderPDF(pdfDataNodes).then((blob) => { + void PDFWorkerComlink.renderPDF(pdfDataNodes, pageSize).then((blob) => { void getBase64FromBlob(blob).then((base64) => { resolve(base64) }) diff --git a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Utils/PDFExport/PDFWorker.tsx b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Utils/PDFExport/PDFWorker.tsx index c8f6eb207..7181c176f 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Utils/PDFExport/PDFWorker.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Utils/PDFExport/PDFWorker.tsx @@ -14,6 +14,7 @@ import { TextProps, SVGProps, ImageWithSrcProp, + PageProps, } from '@react-pdf/renderer' import { expose } from 'comlink' @@ -72,10 +73,11 @@ const Node = ({ node }: { node: PDFDataNode }) => { } } -const PDFDocument = ({ nodes }: { nodes: PDFDataNode[] }) => { +const PDFDocument = ({ nodes, pageSize }: { nodes: PDFDataNode[]; pageSize: PageProps['size'] }) => { return ( { ) } -const renderPDF = (nodes: PDFDataNode[]) => { - return pdf().toBlob() +const renderPDF = (nodes: PDFDataNode[], pageSize: PageProps['size']) => { + return pdf().toBlob() } expose({ diff --git a/packages/web/src/javascripts/Components/SuperEditor/Tools/HeadlessSuperConverter.tsx b/packages/web/src/javascripts/Components/SuperEditor/Tools/HeadlessSuperConverter.tsx index 251d242f7..69c3569b8 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Tools/HeadlessSuperConverter.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/Tools/HeadlessSuperConverter.tsx @@ -56,6 +56,9 @@ export class HeadlessSuperConverter implements SuperConverterServiceInterface { embedBehavior?: PrefValue[PrefKey.SuperNoteExportEmbedBehavior] getFileItem?: (id: string) => FileItem | undefined getFileBase64?: (id: string) => Promise + pdf?: { + pageSize?: PrefValue[PrefKey.SuperNoteExportPDFPageSize] + } }, ): Promise { if (superString.length === 0) { @@ -145,8 +148,8 @@ export class HeadlessSuperConverter implements SuperConverterServiceInterface { resolve() break case 'pdf': { - void import('../Lexical/Utils/PDFExport/PDFExport').then(({ $generatePDFFromNodes }) => { - void $generatePDFFromNodes(this.exportEditor).then((pdf) => { + void import('../Lexical/Utils/PDFExport/PDFExport').then(({ $generatePDFFromNodes }): void => { + void $generatePDFFromNodes(this.exportEditor, config?.pdf?.pageSize || 'A4').then((pdf) => { content = pdf resolve() }) diff --git a/packages/web/src/javascripts/Utils/NoteExportUtils.ts b/packages/web/src/javascripts/Utils/NoteExportUtils.ts index 7a9388876..5f209ff55 100644 --- a/packages/web/src/javascripts/Utils/NoteExportUtils.ts +++ b/packages/web/src/javascripts/Utils/NoteExportUtils.ts @@ -99,6 +99,12 @@ export const getNoteBlob = async ( } return await getBase64FromBlob(fileBlob) }, + pdf: { + pageSize: application.getPreference( + PrefKey.SuperNoteExportPDFPageSize, + PrefDefaults[PrefKey.SuperNoteExportPDFPageSize], + ), + }, }) const useMDFrontmatter = format === 'md' &&