Skip to content

Feature: QuickLook thumbnail cards for pasted/dropped document files #1923

@gjouret

Description

@gjouret

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_thumb.png](assets/document_thumb.png) |
| [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:

  1. 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.
  2. 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 ![](path) 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:

  1. 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.
  2. 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.
  3. External URL support — HTTP/HTTPS links open in the default browser.
  4. Image loading for exportbuildPage() 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions