Summary
When pasting or dragging a non-image file (PDF, SVG, DOCX, PPTX, XLSX, Pages, Keynote, Numbers, etc.) into a note, FSNotes now generates a QuickLook thumbnail of the document and inserts a centered Markdown table with the thumbnail image and a clickable link to the original file:
| Thumbnail |
|:---:|
|  |
| [document.pptx](assets/document.pptx) |
This replaces the previous behavior where non-image files were either inserted as generic file icons (PDF) or plain text links (DOCX, PPTX, etc.).
Supported File Types
Any file type with a macOS QuickLook plugin gets a thumbnail, including:
| Type |
Examples |
| PDF |
.pdf |
| Vector graphics |
.svg |
| Microsoft Office |
.docx, .pptx, .xlsx |
| Apple iWork |
.pages, .keynote, .numbers |
| Other |
Any format with a QuickLook generator |
Regular image files (PNG, JPG, GIF, TIFF, WebP, HEIC) continue to use the existing inline NSTextAttachment rendering — they don't need the thumbnail card since they already display natively.
How It Works
Thumbnail generation
Uses QLThumbnailGenerator (QuickLookThumbnailing framework) to generate a 480×480 thumbnail at screen scale. The thumbnail is saved as a PNG alongside the original file in the note's assets/ directory (TextBundle) or i/ directory (plain notes).
Paste and drag-and-drop
Both paths are handled:
- Paste (Cmd+V): Detects PDF data on the pasteboard (
com.adobe.pdf type), saves it, and generates a thumbnail card. Other document types typically arrive via file URL paste.
- Drag-and-drop from Finder:
performDragOperation() intercepts local file URL drops before handleAttributedText(). Previously, handleAttributedText fired first and inserted non-image files as NSTextAttachment objects with image syntax — causing broken images, crashes (EXC_BAD_ACCESS in updateCounters due to thread-safety race), and no thumbnails.
Inline rendering
After inserting the markdown table, the note is saved to disk synchronously and reloaded via note.load(), which calls loadImagesAndFiles() to convert  patterns into NSTextAttachment objects. This ensures the thumbnail renders inline immediately — not just after app restart.
Asset link handling in Preview mode
Three supporting fixes ensure links work in Preview mode:
- Relative path resolution (
String+.swift createURL(for:)) — resolves paths like assets/file.pdf against the note's directory, since the WKWebView's base URL is MPreview.bundle.
- File opening (
MPreviewView.swift HandlerOpen) — NSWorkspace.shared.open(url) opens files in their default app (e.g., Preview.app for PDFs, Word for DOCX) instead of revealing in Finder.
- External URL support — HTTP/HTTPS links open in the default browser.
- Image loading for export —
buildPage() runs loadImages() for all modes (including print: true used by Share as PDF), so thumbnail images appear in exported PDFs.
Files Changed
| File |
Change |
EditTextView.swift |
Unified saveFileWithThumbnail() using QLThumbnailGenerator; removed PDF-specific savePDFWithThumbnail(); file URL interception in performDragOperation() |
String+.swift |
Relative asset path resolution in createURL(for:) |
MPreviewView.swift |
HandlerOpen: open files/URLs instead of revealing; buildPage(): always run loadImages() |
Previous Issue
Supersedes #1920 (PDF-specific implementation).
🤖 Generated with Claude Code
Summary
When pasting or dragging a non-image file (PDF, SVG, DOCX, PPTX, XLSX, Pages, Keynote, Numbers, etc.) into a note, FSNotes now generates a QuickLook thumbnail of the document and inserts a centered Markdown table with the thumbnail image and a clickable link to the original file:
This replaces the previous behavior where non-image files were either inserted as generic file icons (PDF) or plain text links (DOCX, PPTX, etc.).
Supported File Types
Any file type with a macOS QuickLook plugin gets a thumbnail, including:
.pdf.svg.docx,.pptx,.xlsx.pages,.keynote,.numbersRegular image files (PNG, JPG, GIF, TIFF, WebP, HEIC) continue to use the existing inline
NSTextAttachmentrendering — they don't need the thumbnail card since they already display natively.How It Works
Thumbnail generation
Uses
QLThumbnailGenerator(QuickLookThumbnailing framework) to generate a 480×480 thumbnail at screen scale. The thumbnail is saved as a PNG alongside the original file in the note'sassets/directory (TextBundle) ori/directory (plain notes).Paste and drag-and-drop
Both paths are handled:
com.adobe.pdftype), saves it, and generates a thumbnail card. Other document types typically arrive via file URL paste.performDragOperation()intercepts local file URL drops beforehandleAttributedText(). Previously,handleAttributedTextfired first and inserted non-image files asNSTextAttachmentobjects with image syntax — causing broken images, crashes (EXC_BAD_ACCESS inupdateCountersdue to thread-safety race), and no thumbnails.Inline rendering
After inserting the markdown table, the note is saved to disk synchronously and reloaded via
note.load(), which callsloadImagesAndFiles()to convertpatterns intoNSTextAttachmentobjects. This ensures the thumbnail renders inline immediately — not just after app restart.Asset link handling in Preview mode
Three supporting fixes ensure links work in Preview mode:
String+.swiftcreateURL(for:)) — resolves paths likeassets/file.pdfagainst the note's directory, since the WKWebView's base URL isMPreview.bundle.MPreviewView.swiftHandlerOpen) —NSWorkspace.shared.open(url)opens files in their default app (e.g., Preview.app for PDFs, Word for DOCX) instead of revealing in Finder.buildPage()runsloadImages()for all modes (includingprint: trueused by Share as PDF), so thumbnail images appear in exported PDFs.Files Changed
EditTextView.swiftsaveFileWithThumbnail()usingQLThumbnailGenerator; removed PDF-specificsavePDFWithThumbnail(); file URL interception inperformDragOperation()String+.swiftcreateURL(for:)MPreviewView.swiftHandlerOpen: open files/URLs instead of revealing;buildPage(): always runloadImages()Previous Issue
Supersedes #1920 (PDF-specific implementation).
🤖 Generated with Claude Code