Skip to content

feat: render local PNG/image files in WYSIWYG editor#9

Merged
gdilla merged 1 commit intomainfrom
feat/png-rendering
Mar 15, 2026
Merged

feat: render local PNG/image files in WYSIWYG editor#9
gdilla merged 1 commit intomainfrom
feat/png-rendering

Conversation

@gdilla
Copy link
Owner

@gdilla gdilla commented Mar 14, 2026

Summary

  • Local images referenced with relative paths (e.g. ![photo](assets/photo.png)) now render correctly in the Tiptap WYSIWYG editor
  • Uses Tauri's convertFileSrc + asset protocol to convert relative filesystem paths to URLs the webview can load
  • Round-trip safe: asset URLs are stripped back to relative paths when serializing to markdown

What changed

  • src-tauri/tauri.conf.json — Enable asset protocol with wildcard scope
  • src-tauri/Cargo.toml — Add protocol-asset feature to Tauri dependency
  • src/utils/imagePathResolver.ts (new) — resolveImagePaths / unresolveImagePaths / resolveRelativeSrc utilities
  • src/components/Editor.vue — Wrap markdownToHtml/htmlToMarkdown calls with path resolution via mdToHtml/htmlToMd helpers
  • src/extensions/GdownImage.ts — Resolve relative paths in drag-drop and paste handlers
  • src/extensions/MarkdownImageInputRule.ts — Resolve relative paths when ![alt](path) input rule fires
  • src/__tests__/setup.ts — Add convertFileSrc mock to Tauri API
  • src/__tests__/utils/imagePathResolver.test.ts (new) — 33 tests covering resolve, unresolve, round-trip, and edge cases

How it works

  1. Loading: markdownToHtml() output is post-processed — relative <img src="assets/..."> becomes <img src="http://asset.localhost/absolute/path/..." data-original-src="assets/...">
  2. Saving: getHTML() output is post-processed — asset URLs restored to relative paths via data-original-src or prefix stripping
  3. Input rule / Drag-drop / Paste: Paths resolved at insertion time using convertFileSrc

Test plan

  • 33 new unit tests pass for image path resolution
  • All 222 existing tests pass
  • TypeScript typecheck clean
  • ESLint clean (0 new warnings)
  • Clippy clean
  • Manual: open a .md file with ![](assets/image.png) — image renders in WYSIWYG mode
  • Manual: drag-drop a PNG into the editor — image renders and saves as relative path
  • Manual: paste an image — renders and saves correctly
  • Manual: switch WYSIWYG ↔ Source — image paths preserved as relative markdown
  • Manual: type ![alt](assets/test.png) — image renders via input rule

🤖 Generated with Claude Code

Local images referenced with relative paths (e.g. `assets/photo.png`)
now render correctly in the Tiptap editor. The webview can't resolve
paths relative to the document directory, so we convert them to Tauri
asset protocol URLs (`http://asset.localhost/...`) on load and strip
them back to relative paths on save.

Changes:
- Enable Tauri `protocol-asset` feature and asset protocol scope
- Add `imagePathResolver.ts` utility (resolve/unresolve image paths)
- Wrap markdownToHtml/htmlToMarkdown in Editor.vue with path resolution
- Resolve paths in GdownImage drag/drop/paste and input rule handlers
- Add `convertFileSrc` to test setup mock
- 33 new tests for image path resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gdilla gdilla merged commit cf5b943 into main Mar 15, 2026
1 check failed
@gdilla gdilla deleted the feat/png-rendering branch March 15, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant