diff --git a/packages/ui-services/src/Archive/ArchiveManager.ts b/packages/ui-services/src/Archive/ArchiveManager.ts index e24cc89dd..62f15f55d 100644 --- a/packages/ui-services/src/Archive/ArchiveManager.ts +++ b/packages/ui-services/src/Archive/ArchiveManager.ts @@ -19,9 +19,9 @@ function zippableFileName(name: string, suffix = '', format = 'txt'): string { return sanitizedName.slice(0, maxFileNameLength - nameEnd.length) + nameEnd } -export function parseAndCreateZippableFileName(name: string) { +export function parseAndCreateZippableFileName(name: string, suffix = '') { const { name: parsedName, ext } = parseFileName(name) - return zippableFileName(parsedName, '', ext) + return zippableFileName(parsedName, suffix, ext) } type ZippableData = { diff --git a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx index 8d96ca118..4a4405451 100644 --- a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx +++ b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx @@ -1,7 +1,7 @@ import Icon from '@/Components/Icon/Icon' import { observer } from 'mobx-react-lite' import { useState, useEffect, useMemo, useCallback } from 'react' -import { NoteType, Platform, SNNote } from '@standardnotes/snjs' +import { NoteType, Platform, SNNote, pluralize } from '@standardnotes/snjs' import { CHANGE_EDITOR_WIDTH_COMMAND, OPEN_NOTE_HISTORY_COMMAND, @@ -99,6 +99,13 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => { }, []) const downloadSelectedItems = useCallback(async () => { + if (notes.length === 0) { + return + } + const toast = addToast({ + type: ToastType.Progress, + message: `Exporting ${notes.length} ${pluralize(notes.length, 'note', 'notes')}...`, + }) try { const result = await createNoteExport(application, notes) if (!result) { @@ -113,12 +120,14 @@ const NotesOptions = ({ notes, closeMenu }: NotesOptionsProps) => { filename: fileName, isNativeMobileWeb: application.isNativeMobileWeb(), }) + dismissToast(toast) } catch (error) { console.error(error) addToast({ type: ToastType.Error, message: 'Could not export notes', }) + dismissToast(toast) } }, [application, notes]) diff --git a/packages/web/src/javascripts/Utils/NoteExportUtils.ts b/packages/web/src/javascripts/Utils/NoteExportUtils.ts index e09be6fee..17b65bbff 100644 --- a/packages/web/src/javascripts/Utils/NoteExportUtils.ts +++ b/packages/web/src/javascripts/Utils/NoteExportUtils.ts @@ -1,8 +1,16 @@ import { WebApplication } from '@/Application/WebApplication' import { HeadlessSuperConverter } from '@/Components/SuperEditor/Tools/HeadlessSuperConverter' -import { NoteType, PrefKey, SNNote, PrefDefaults, FileItem, PrefValue, pluralize } from '@standardnotes/snjs' -import { WebApplicationInterface, parseAndCreateZippableFileName, sanitizeFileName } from '@standardnotes/ui-services' +import { NoteType, PrefKey, SNNote, PrefDefaults, FileItem, PrefValue } from '@standardnotes/snjs' +import { WebApplicationInterface, parseAndCreateZippableFileName } from '@standardnotes/ui-services' import { ZipDirectoryEntry } from '@zip.js/zip.js' +// @ts-expect-error Using inline loaders to load CSS as string +import superEditorCSS from '!css-loader!sass-loader!../Components/SuperEditor/Lexical/Theme/editor.scss' +// @ts-expect-error Using inline loaders to load CSS as string +import snColorsCSS from '!css-loader!sass-loader!@standardnotes/styles/src/Styles/_colors.scss' +// @ts-expect-error Using inline loaders to load CSS as string +import exportOverridesCSS from '!css-loader!sass-loader!../Components/SuperEditor/Lexical/Theme/export-overrides.scss' +import { getBase64FromBlob } from './Utils' +import { parseFileName } from '@standardnotes/filepicker' export const getNoteFormat = (application: WebApplicationInterface, note: SNNote) => { if (note.noteType === NoteType.Super) { @@ -25,15 +33,6 @@ export const getNoteFileName = (application: WebApplicationInterface, note: SNNo const headlessSuperConverter = new HeadlessSuperConverter() -// @ts-expect-error Using inline loaders to load CSS as string -import superEditorCSS from '!css-loader!sass-loader!../Components/SuperEditor/Lexical/Theme/editor.scss' -// @ts-expect-error Using inline loaders to load CSS as string -import snColorsCSS from '!css-loader!sass-loader!@standardnotes/styles/src/Styles/_colors.scss' -// @ts-expect-error Using inline loaders to load CSS as string -import exportOverridesCSS from '!css-loader!sass-loader!../Components/SuperEditor/Lexical/Theme/export-overrides.scss' -import { getBase64FromBlob } from './Utils' -import { ToastType, addToast, dismissToast } from '@standardnotes/toast' - const superHTML = (note: SNNote, content: string) => `
@@ -175,11 +174,6 @@ export const createNoteExport = async ( return } - const toast = addToast({ - type: ToastType.Progress, - message: `Exporting ${notes.length} ${pluralize(notes.length, 'note', 'notes')}...`, - }) - const superExportFormatPref = application.getPreference( PrefKey.SuperNoteExportFormat, PrefDefaults[PrefKey.SuperNoteExportFormat], @@ -192,7 +186,6 @@ export const createNoteExport = async ( if (notes.length === 1 && !noteRequiresFolder(notes[0], superExportFormatPref, superEmbedBehaviorPref)) { const blob = await getNoteBlob(application, notes[0], superEmbedBehaviorPref) const fileName = getNoteFileName(application, notes[0]) - dismissToast(toast) return { blob, fileName, @@ -211,31 +204,37 @@ export const createNoteExport = async ( await addEmbeddedFilesToFolder(application, notes[0], root) const zippedBlob = await zipFS.exportBlob() - dismissToast(toast) return { blob: zippedBlob, fileName: fileName + '.zip', } } + const filenameCounts: Record