Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ The following changes are implemented on `main` after `v3.9.4` but are not yet p
- Show secure-backup choices only when Backup is opened.
- Load the ZIP engine and calculate detailed storage usage only when those features are requested, leaving startup and normal document-opening paths unchanged.

### GitHub Import

- Removed the 30-file display cap so repository and folder results expose every Markdown file found.
- Added complete subtree traversal when GitHub marks a recursive repository tree response as truncated.
- Added branch, tag, and commit URL resolution, including branch names containing `/`, and pinned each import to the resolved immutable commit SHA.
- Added optional private repository access that accepts fine-grained and classic PATs automatically.
- Kept private access session-only: named tokens remain in memory, disappear on reload or app close, support an optional earlier expiry date, and can be removed individually without a passphrase or unlock step. Retired locally saved GitHub-access records are deleted during upgrade.
- Replaced the verbose token form with a compact add-then-select flow. Add/remove success and failure use application toasts instead of expanding the form with inline status text.
- Restored the compact 520px GitHub URL step while keeping the searchable file picker at 760px. Repository name and ref metadata share one line; explicit tree/blob URLs show the branch or ref, while repository URLs show only the resolved commit.
- Added file search, a compact selected-count badge, borderless toolbar-style controls for select/deselect all and collapse/expand all, and GitHub-style folder and file rows using the application typography scale.
- Changed local, drag-and-drop, desktop, and GitHub Markdown imports to save documents in Explorer without opening every imported file as a tab.
- Batched multi-tab close commands so closing hundreds of tabs performs one state update and render instead of repeatedly rebuilding the interface.

---

## v3.9.4
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Turn a document into a Share Snapshot link for quick handoffs, or start access-c
<img src="https://github.com/user-attachments/assets/bbacabcf-eb19-4430-af19-1ab791afe01c" alt="3D STL Full screen" width="90%" />
</p>

- **Import and export:** open local files or public GitHub content; export Markdown, standalone HTML, PNG, Browser Print/Save as PDF, or a legacy raster PDF.
- **Import and export:** open local files or GitHub content from branches, tags, commits, and optionally private repositories; export Markdown, standalone HTML, PNG, Browser Print/Save as PDF, or a legacy raster PDF.

- **Optional sharing:** create a Share Snapshot with View only or Can edit access, or start a temporary Live Share room with host, Can edit, and View only capabilities.

Expand Down Expand Up @@ -110,7 +110,7 @@ Markdown Viewer is local-first, not network-free. The following table shows the
| :--- | :--- |
| Editing, local imports, Preview, Workspace autosave, and most exports | On the device |
| Web libraries and uncached renderer dependencies | CDN requests in the web/PWA build |
| Public GitHub import and emoji lookup | GitHub APIs and raw-content hosts |
| GitHub import and emoji lookup | Public content uses GitHub APIs and raw-content hosts; private content uses an optional PAT only with `api.github.com` |
| PlantUML, D2, Graphviz, Vega-Lite, WaveDrom, and some diagram previews | Diagram source can be sent to PlantUML, Kroki, or mermaid.ink |
| Consented image, GIF, and video insertion | Public, content-addressed Cloudflare media storage for 90 days |
| Large Share Snapshot | Cloudflare KV for 90 days |
Expand Down Expand Up @@ -156,7 +156,9 @@ Remote renderer services receive the source of the diagram they render. Do not s
- Importing a workspace backup permanently replaces the current workspace after confirmation.
- Workspace backups do not include trash, desktop history, or crash-recovery journals.
- A local Markdown file larger than 10 MB is rejected.
- The public GitHub importer shows at most 30 Markdown files for a repository or folder result.
- The searchable GitHub importer shows every Markdown file found in a repository or folder result and resolves branch, tag, and commit URLs to an immutable commit SHA.
- Private repository access accepts fine-grained and classic PATs automatically. Multiple named tokens can be added, selected, and removed during the current session, with an optional earlier expiry date; tokens are held only in memory and disappear on reload or app close.
- Imported Markdown files are saved to Explorer and remain closed until you choose one, preventing large imports from flooding the tab bar.
- Managed source media is limited to 25 MiB before processing; stored payload limits are 300 KiB for still images, 5 MiB for GIFs, and 10 MiB for videos.
- Stored Share Snapshot content is limited to 8,000,000 characters and expires after 90 days.
- Live Share allows up to 64 WebSocket participants and 8 MB per live message.
Expand Down
3 changes: 3 additions & 0 deletions assets/lucide-icons.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 84 additions & 4 deletions desktop-app/resources/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1281,19 +1281,99 @@ <h2 class="about-title">Markdown Viewer</h2>
<div class="modal-header">
<div>
<p id="github-import-title" class="reset-modal-message">Import Markdown from GitHub</p>
<p class="modal-subtext">Paste a GitHub file or repository URL.</p>
<p id="github-import-subtitle" class="modal-subtext">Paste a GitHub file or repository URL.</p>
</div>
<button type="button" class="modal-close-btn" id="github-import-close" aria-label="Close GitHub import dialog"><i class="lucide lucide-x" aria-hidden="true"></i></button>
</div>
<div class="modal-body github-import-modal-body">
<label class="reset-modal-label" id="github-import-url-label" for="github-import-url">GitHub URL</label>
<input type="url" id="github-import-url" class="rename-modal-input" placeholder="https://github.com/owner/repo/blob/main/README.md" autocomplete="url" spellcheck="false" />
<section id="github-import-access" class="github-import-access" aria-labelledby="github-import-access-title">
<button type="button" id="github-import-access-toggle" class="github-import-access-toggle" aria-expanded="false" aria-controls="github-import-access-panel">
<span class="github-import-access-icon" aria-hidden="true"><i class="lucide lucide-shield-check"></i></span>
<span class="github-import-access-copy">
<span id="github-import-access-title" class="github-import-access-title">Private repository access</span>
<span id="github-import-access-summary" class="github-import-access-summary">No access token added</span>
</span>
<i class="lucide lucide-chevron-down github-import-access-chevron" aria-hidden="true"></i>
</button>
<div id="github-import-access-panel" class="github-import-access-panel" hidden>
<div id="github-import-access-manage" class="github-import-access-manage" hidden>
<div class="github-import-access-manage-header">
<label class="reset-modal-label" for="github-import-pat-select">Access token</label>
<div class="github-import-toolbar-actions" role="group" aria-label="Access token actions">
<button type="button" id="github-import-pat-add-another" class="tool-button document-command-btn github-import-toolbar-btn" aria-label="Add another access token" title="Add another access token">
<i class="lucide lucide-plus" aria-hidden="true"></i>
</button>
<button type="button" id="github-import-pat-remove" class="tool-button document-command-btn github-import-toolbar-btn github-import-remove-token-btn" aria-label="Remove selected access token" title="Remove selected access token">
<i class="lucide lucide-trash-2" aria-hidden="true"></i>
</button>
</div>
</div>
<select id="github-import-pat-select" class="rename-modal-input"></select>
<span id="github-import-access-selected-meta" class="github-import-access-selected-meta"></span>
</div>
<div id="github-import-access-form" class="github-import-access-form">
<div class="github-import-access-form-heading">
<strong>Add access token</strong>
<button type="button" id="github-import-pat-add-cancel" class="tool-button document-command-btn github-import-toolbar-btn" aria-label="Cancel adding access token" title="Cancel" hidden>
<i class="lucide lucide-x" aria-hidden="true"></i>
</button>
</div>
<div class="github-import-access-field">
<label class="reset-modal-label" for="github-import-pat-name">Token name</label>
<input type="text" id="github-import-pat-name" class="rename-modal-input" maxlength="60" placeholder="My access token" autocomplete="off" spellcheck="false" />
</div>
<div class="github-import-access-field">
<label class="reset-modal-label" for="github-import-pat-expiry">Expiry date <span class="github-import-optional-label">(optional)</span></label>
<input type="datetime-local" id="github-import-pat-expiry" class="rename-modal-input" autocomplete="off" />
</div>
<div class="github-import-access-field github-import-access-token-field">
<label class="reset-modal-label" for="github-import-pat">Personal access token</label>
<input type="password" id="github-import-pat" class="rename-modal-input" autocomplete="off" spellcheck="false" />
</div>
<div class="github-import-access-form-footer">
<span class="github-import-access-session-note">Available for this session</span>
<button type="button" id="github-import-pat-save" class="reset-modal-btn">Add access</button>
</div>
</div>
</div>
</section>
<select id="github-import-file-select" class="rename-modal-input" aria-label="Select Markdown files" style="display:none;"></select>
<div id="github-import-repository-context" class="github-import-repository-context" hidden>
<span class="github-import-repository-icon" aria-hidden="true"><i class="bi bi-github"></i></span>
<div class="github-import-repository-copy">
<div class="github-import-repository-heading">
<strong id="github-import-repository-name"></strong>
</div>
<div class="github-import-repository-meta">
<span id="github-import-ref-item" class="github-import-ref"><i class="lucide lucide-git-branch" aria-hidden="true"></i><span id="github-import-ref"></span></span>
<a id="github-import-commit-link" class="github-import-commit-link" target="_blank" rel="noopener noreferrer">
<i class="lucide lucide-git-commit-horizontal" aria-hidden="true"></i>
<span id="github-import-commit"></span>
</a>
<span id="github-import-base-path" class="github-import-base-path" hidden></span>
</div>
</div>
</div>
<div id="github-import-selection-toolbar" class="github-import-selection-toolbar" style="display:none;">
<span id="github-import-selected-count" class="github-import-selected-count">0 selected</span>
<button type="button" class="reset-modal-btn" id="github-import-select-all">Select all</button>
<label class="github-import-search" for="github-import-search">
<i class="lucide lucide-search" aria-hidden="true"></i>
<input type="search" id="github-import-search" placeholder="Search Markdown files" autocomplete="off" spellcheck="false" />
</label>
<div class="github-import-selection-actions">
<output id="github-import-selected-count" class="github-import-selected-count" aria-live="polite">0 selected</output>
<div class="github-import-toolbar-actions" role="group" aria-label="File tree actions">
<button type="button" class="tool-button document-command-btn github-import-toolbar-btn" id="github-import-toggle-folders" aria-label="Collapse all folders" title="Collapse all folders">
<i class="lucide lucide-fold-vertical" aria-hidden="true"></i>
</button>
<button type="button" class="tool-button document-command-btn github-import-toolbar-btn" id="github-import-select-all" aria-label="Select all files" title="Select all files">
<i class="lucide lucide-check-check" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
<div id="github-import-tree" class="github-import-tree" style="display:none;"></div>
<div id="github-import-tree" class="github-import-tree" role="tree" aria-label="Markdown files in this GitHub location" style="display:none;"></div>
<p id="github-import-error" class="github-import-error" role="status" style="display:none;"></p>
</div>
<div class="reset-modal-actions">
Expand Down
Loading
Loading