diff --git a/src/lib/extensions/file-attachment.ts b/src/lib/extensions/file-attachment.ts index ab19e3f..fcce83b 100644 --- a/src/lib/extensions/file-attachment.ts +++ b/src/lib/extensions/file-attachment.ts @@ -24,12 +24,27 @@ export const FileAttachment = Node.create({ return { src: { default: null, + parseHTML: element => element.getAttribute('data-src'), + renderHTML: attributes => { + if (!attributes.src) return {}; + return { 'data-src': attributes.src }; + }, }, filename: { default: null, + parseHTML: element => element.getAttribute('data-filename'), + renderHTML: attributes => { + if (!attributes.filename) return {}; + return { 'data-filename': attributes.filename }; + }, }, filesize: { default: null, + parseHTML: element => element.getAttribute('data-filesize'), + renderHTML: attributes => { + if (!attributes.filesize) return {}; + return { 'data-filesize': attributes.filesize }; + }, } }; }, @@ -50,17 +65,17 @@ export const FileAttachment = Node.create({ const isPdf = filename.toLowerCase().endsWith('.pdf'); if (isPdf) { - return ['div', mergeAttributes(this.options.HTMLAttributes, { + return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 'data-type': 'file-attachment', - 'data-src': HTMLAttributes.src, - 'data-filename': HTMLAttributes.filename, class: 'file-attachment-wrapper relative w-full my-4 rounded-xl overflow-hidden border border-border flex min-h-[500px] bg-muted/20 group' }), ['iframe', { src: HTMLAttributes.src, class: 'w-full h-full border-0 absolute inset-0' }] ]; } - return ['div', mergeAttributes(this.options.HTMLAttributes, { 'data-type': 'file-attachment', 'data-src': HTMLAttributes.src, 'data-filename': HTMLAttributes.filename }), + return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + 'data-type': 'file-attachment', + }), ['a', { href: HTMLAttributes.src, target: '_blank', rel: 'noopener noreferrer', class: 'file-attachment-link flex items-center p-3 gap-3 w-full h-full' }, ['div', { class: 'flex-shrink-0 flex items-center justify-center w-10 h-10 rounded-md bg-primary/10 text-primary' }, // SVG for FileText @@ -116,6 +131,7 @@ export const FileAttachment = Node.create({ wrapper.setAttribute('data-type', 'file-attachment'); wrapper.setAttribute('data-src', node.attrs.src); wrapper.setAttribute('data-filename', node.attrs.filename); + wrapper.setAttribute('data-filesize', node.attrs.filesize); if (isFramable) { // Framed mode matching FileViewer diff --git a/src/store/index.ts b/src/store/index.ts index 5e89168..47a92de 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -626,16 +626,18 @@ export const cleanupNoteAttachments = async (noteId: string) => { if (!pb.authStore.isValid) return; try { - const note = store.notes.find(n => n.id === noteId); - if (!note) return; - const record = await pb.collection(NOTES_COLLECTION).getOne(noteId); if (!record.attachments || record.attachments.length === 0) return; - const content = note.content || ""; + const content = record.content || ""; const filesToDelete: string[] = []; + + // Also check decoded content just in case of encoding mismatches + const decodedContent = decodeURIComponent(content); + for (const filename of record.attachments) { - if (!content.includes(filename)) { + // Check for literal filename OR the part of the URL that includes the filename + if (!content.includes(filename) && !decodedContent.includes(filename)) { filesToDelete.push(filename); } } @@ -655,16 +657,16 @@ export const cleanupTaskAttachments = async (taskId: string) => { if (!pb.authStore.isValid) return; try { - const task = store.tasks.find(t => t.id === taskId); - if (!task) return; - const record = await pb.collection(TASGRID_COLLECTION).getOne(taskId); if (!record.attachments || record.attachments.length === 0) return; - const content = task.content || ""; + const content = record.content || ""; const filesToDelete: string[] = []; + + const decodedContent = decodeURIComponent(content); + for (const filename of record.attachments) { - if (!content.includes(filename)) { + if (!content.includes(filename) && !decodedContent.includes(filename)) { filesToDelete.push(filename); } }