Date: 2026-01-05 Status: Draft
Enable the Host App (Markdown.app) to fully browse, read, and render Markdown files, including:
- Opening local
.mdfiles via Finder or "Open" dialog. - Rendering local images referenced in Markdown (e.g.,
). - Handling links (external to browser, internal
.mdto app). - Basic interactions (scrolling, copy).
The Host App will use SwiftUI's document-based app lifecycle (DocumentGroup) to manage windows and files.
graph TD
A[App (SwiftUI)] --> B[DocumentGroup]
B --> C[MarkdownDocument]
C --> D[MarkdownEditorView]
D --> E[MarkdownWebView]
E --> F[WKWebView (AppKit)]
F --> G[WebRenderer (JS/TS)]
- Conforms to
FileDocument. - Responsibilities: Reading/Writing text content. (Initially Read-Only focus, but ready for Write).
- Crucial: Maintains the
URLof the file to determine the Base Path for images.
- Wraps
WKWebView. - Loads the
index.htmlfrom the App Bundle (to ensurebundle.jsand CSS load correctly). - Communicates with JS via
evaluateJavaScriptandWKScriptMessageHandler. - Config:
allowFileAccessFromFileURLs = true: To allow loading local images fromfile://when the main page is alsofile://(bundle).developerExtrasEnabled = true(Debug only).
- Updates required in
web-renderer/src/index.ts. - New Function:
renderMarkdown(content: string, options: { baseUrl: string }). - Logic:
- When rendering, if an image path is relative, prepend
baseUrl. - Use
markdown-itcustom image rule or post-processing.
- When rendering, if an image path is relative, prepend
Challenge: The WebView loads index.html from the App Bundle (/Applications/.../Resources/dist/index.html). A markdown file is in ~/Documents/Doc.md. A relative image  resolves to /Applications/.../Resources/dist/pic.png (Fail).
Solution:
-
Swift Side:
- Obtain the absolute path of the Markdown file (e.g.,
/Users/me/Docs/). - Pass this path to JS as
baseUrl(must end with/). - Sandbox Note: The App has access to the file via
DocumentGroup(Security Scoped URL). TheWKWebViewgenerally inherits the App's read capabilities for file URLs ifreadAccessURLis handled or if "User Selected File" entitlement is active and we use absolute paths.
- Obtain the absolute path of the Markdown file (e.g.,
-
JS Side:
- Customize
markdown-itimage renderer. - If
srcis not absolute (doesn't start withhttp,https,file:), prependbaseUrl. - Result:
<img src="file:///Users/me/Docs/pic.png">.
- Customize
Challenge: Users click links.
[Google](https://google.com)-> Should open in Safari.[Next Chapter](part2.md)-> Should open in a new App Window.
Solution:
- Implement
WKNavigationDelegate.webView(_:decidePolicyFor:decisionHandler:). - Logic:
navigationType == .linkActivated- If URL is
http/https:NSWorkspace.shared.open(url),decision = .cancel. - If URL is
fileand ends with.md:NSWorkspace.shared.open(url)(Triggers App to open new document),decision = .cancel. - Else:
decision = .allow.
- Modify
web-renderer/src/index.ts.- Update
renderMarkdownsignature to acceptconfigobject. - Implement image path rewriting logic.
- Update
- Rebuild renderer (
npm run build).
- Create
MarkdownDocumentstruct. - Update
MarkdownAppto useDocumentGroup. - Create
MarkdownWebView(wrapping the existing logic fromPreviewViewControllerbut adapted for SwiftUI).
- Test opening a file with images.
- Verify sandbox access (may need
startAccessingSecurityScopedResourcefor the folder if strict).- Note: Usually
DocumentGrouphandles the file access, but images next to the file might technically be outside the "file's" scope unless we ask for Folder access or macOS assumes related resources. - Fallback: If images fail to load due to sandbox, we might need to ask user for permission to the Folder, or use a "Project" based approach. For now, we assume macOS's standard
user-selected.read-onlymight be lenient enough for adjacent files, or we might hit a wall. - Correction:
user-selected.read-onlygrants access ONLY to the selected file. Adjacent images will FAIL to load in Sandboxed app unless the user selects the Folder or we use a specific entitlement/hack. - Refined Solution for Images:
- Start simple: Try to read.
- If blocked: We might need to implement a mechanism where the user grants access to the "Parent Folder".
- Alternative: Disable Sandbox (Not recommended/allowed for App Store).
- Realistic MVP: Just handle the file for now. If images fail, we log it. Addendum: For a robust "Markdown Editor/Viewer", opening the Folder is the standard pattern (VSCode style), or relying on the OS believing the image is related.
- Note: Usually
- Auto-Refresh: Watch file for changes.
- Scroll Sync: Bi-directional scrolling.
- Dark Mode Sync: Real-time theme switching.