Skip to content

Commit 3f1b3ca

Browse files
Merge pull request #226 from ThisIs-Developer/agent/improve-file-image-drag-drop
feat(editor): add persistent media and improve file workflows
2 parents 54bf436 + 97b2c60 commit 3f1b3ca

37 files changed

Lines changed: 3886 additions & 559 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
All notable code changes to **Markdown Viewer** are documented here.
44
Non-code commits (documentation, planning, README-only updates) are excluded.
55

6+
## Unreleased
7+
8+
- **Media upload, file drag-and-drop, and GitHub folders:** Replaced the blocking full-window drop overlay with a compact notice, made folder-targeted Markdown imports land in the selected folder, kept untargeted imports at the default workspace root, added hover-to-expand folders and Explorer edge auto-scrolling, and added a Markdown-style file drag preview. GitHub imports now recreate the repository's nested directory tree inside its repository-named folder, and the mobile Explorer filter bar now matches the compact 44 px search-control height. Uploaded, pasted, and dropped images now use short 90-day content-addressed links; animated GIFs retain animation, and MP4, WebM, and Ogg videos insert as sanitized playable media. Upload progress and every user-facing toast now share the GitHub-import toast position, while unsupported files show a red "File not supported" alert with recovery guidance. Right-clicking blank Explorer space offers New file and New folder, and existing embedded raster images can still be converted automatically after consent.
9+
610
## v3.9.3
711

812
- **Description:** Redesigned the Markdown Viewer workspace around a professional document Explorer, streamlined toolbar, responsive navigation, consistent icon system, and complete interface localization.

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ For the full feature list, details, limitations, and privacy notes, see the [fea
106106
## Markdown Editing and Live Preview
107107

108108
- Write plain Markdown in a focused editor while the live preview renders GitHub-Flavored Markdown, syntax highlighting, math, alerts, footnotes, tables, task lists, and sanitized HTML.
109-
- Organize up to 50 Markdown files in a closable, responsive left sidebar with a persistent tab-strip toggle, fixed Default and Secret workspaces, one-level folders, search, Recent, Favorites, single-click opening, and drag-and-drop moves. Secret Workspace content is password-encrypted on the device, and multi-file imports show compact progress without blocking the editor.
109+
- Organize up to 50 Markdown files in a closable, responsive left sidebar with a persistent tab-strip toggle, fixed Default and Secret workspaces, one-level folders, search, Recent, Favorites, single-click opening, precise drag-and-drop moves, hover-to-expand folders, and edge auto-scrolling. Secret Workspace content is password-encrypted on the device, and multi-file imports show compact progress without blocking the editor.
110+
- Paste, upload, or drop images, animated GIFs, and MP4, WebM, or Ogg videos at the editor cursor. A GitHub-import-style toast reports media upload progress, and managed media uses short content-addressed HTTPS links that remain usable across refreshes, Share Snapshot, Live Share, and Markdown export until their 90-day expiry. Existing inline raster data can be converted after the same first-use consent.
110111
- Use WYSIWYG-style toolbar helpers for common Markdown syntax while keeping full control of the plain-text Markdown source.
111112
- Preview large documents with debounced rendering and a background worker so typing stays responsive.
112113

@@ -234,6 +235,7 @@ Markdown-Viewer/
234235
+-- preview-worker.js # Markdown preview worker
235236
+-- sw.js # Service worker cache behavior
236237
+-- assets/ # App images and icons
238+
| +-- i18n/ # Interface catalogs and locale generator
237239
+-- functions/ # Cloudflare Pages Functions
238240
+-- workers/ # Live Share Worker source
239241
+-- desktop-app/ # Neutralinojs desktop build
@@ -271,14 +273,14 @@ Some advanced diagram engines use remote renderers such as PlantUML, Kroki, or m
271273

272274
Markdown Viewer is not a cloud workspace. Normal typing, preview rendering, local file import, tab autosave, theme settings, and most exports happen on your device. No login is required, and the app does not implement analytics, telemetry, ads, or tracking cookies.
273275

274-
Network use is user-triggered for features such as GitHub import, remote diagram renderers, Share Snapshot, Live Share, CDN libraries, and external document assets. Private mode in Workspace settings keeps document content, workspace state, and review feedback session-only while editing and review tools remain available. For the full reference, read the [data handling summary](wiki/Features.md#data-handling-summary).
276+
Network use is user-triggered for features such as consented managed-media upload, GitHub import, remote diagram renderers, Share Snapshot, Live Share, CDN libraries, and external document assets. Private mode in Workspace settings keeps document content, workspace state, and review feedback session-only while editing and review tools remain available. For the full reference, read the [data handling summary](wiki/Features.md#data-handling-summary).
275277

276278
## Security and Privacy Controls
277279

278280
- Preview HTML is sanitized before insertion, and exported HTML includes a restrictive CSP plus SRI metadata for its external assets.
279281
- Secret Workspace derives a local encryption key from the user's password with PBKDF2-SHA-256 and encrypts its files and folder names with AES-GCM. The key is kept only for the unlocked browser session, and forgotten passwords cannot be recovered.
280282
- Cloudflare Pages deployments use `_headers` for CSP, clickjacking protection, referrer and permissions policies, and no-sniff protection; sensitive paths are redirected to 404 responses.
281-
- Stored Share Snapshot API CORS is limited to the production app, `null`, and local development origins. Stored responses are `no-store`, and creators receive a deletion token from the API.
283+
- Managed media and stored Share Snapshot API uploads are limited to the production app, previews, `null`, and local development origins. Managed images, GIFs, and videos are public through unguessable immutable links for 90 days; stored snapshot responses are `no-store`, and snapshot creators receive a deletion token from the API.
282284
- STL rendering rejects oversized sources, non-finite geometry, and excessive vertex counts before WebGL rendering.
283285
- The Neutralino desktop build removes the default `os.execCommand` exposure and keeps native APIs on an explicit allowlist. See the [security model](wiki/Features.md#security-model) and [configuration reference](wiki/Configuration.md#share-api).
284286

_headers

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
3-
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'none'; script-src 'self' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://esm.sh 'sha256-DgMFO4QE+qqf2xNgeNb5gMKG6BtiiQFniYj21c88yME=' 'sha256-NnbK2LG1LUwYyZ1xgJN7k3oK4oTvHY4o9852VxwNA/o='; script-src-attr 'none'; worker-src 'self'; connect-src 'self' https://api.github.com https://raw.githubusercontent.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://esm.sh https://kroki.io https://www.plantuml.com https://mermaid.ink https://paulrosen.github.io wss://markdownviewer.pages.dev; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; style-src-attr 'unsafe-inline'; font-src 'self' data: https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; media-src 'self' blob: data:; manifest-src 'self'; frame-src 'none'; upgrade-insecure-requests
3+
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'none'; script-src 'self' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://esm.sh 'sha256-DgMFO4QE+qqf2xNgeNb5gMKG6BtiiQFniYj21c88yME=' 'sha256-NnbK2LG1LUwYyZ1xgJN7k3oK4oTvHY4o9852VxwNA/o='; script-src-attr 'none'; worker-src 'self'; connect-src 'self' https://markdownviewer.pages.dev https://api.github.com https://raw.githubusercontent.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://esm.sh https://kroki.io https://www.plantuml.com https://mermaid.ink https://paulrosen.github.io wss://markdownviewer.pages.dev; img-src 'self' data: blob: https:; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; style-src-attr 'unsafe-inline'; font-src 'self' data: https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; media-src 'self' blob: data: https:; manifest-src 'self'; frame-src 'none'; upgrade-insecure-requests
44
X-Frame-Options: DENY
55
X-Content-Type-Options: nosniff
66
Referrer-Policy: strict-origin-when-cross-origin

assets/i18n/de.json

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
", file location": ", Dateispeicherort",
1212
", locked": ", gesperrt",
1313
", or": ", oder",
14-
".md or .markdown files supported": ".md- oder .markdown-Dateien werden unterstützt",
1514
"\" style=\"width:100%; height:100%; display:flex; align-items:center; justify-content:center; overflow:hidden;\">": "\" style=\"width:100%; Höhe: 100 %; Anzeige:flex; align-items:center; justify-content:center; overflow:hidden;\">",
1615
"{{0}} characters": "{{0}} Zeichen",
1716
"{{0}} details go here.": "{{0}} Details finden Sie hier.",
@@ -64,7 +63,6 @@
6463
"All changes saved": "Alle Änderungen gespeichert",
6564
"All workspace folders collapsed.": "Alle Arbeitsbereichsordner wurden minimiert.",
6665
"All workspace folders expanded.": "Alle Arbeitsbereichsordner erweitert.",
67-
"Alt Text (used for title)": "Alt-Text (wird für den Titel verwendet)",
6866
"Apache License 2.0": "Apache-Lizenz 2.0",
6967
"Appearance": "Aussehen",
7068
"Application information": "Anwendungsinformationen",
@@ -95,7 +93,6 @@
9593
"Cancel feedback": "Feedback abbrechen",
9694
"Cancel Image generation": "Bilderzeugung abbrechen",
9795
"Cancel PDF generation": "PDF-Generierung abbrechen",
98-
"Cannot import: The selected file appears to be a binary file.": "Import nicht möglich: Die ausgewählte Datei scheint eine Binärdatei zu sein.",
9996
"Capturing document": "Dokument erfassen",
10097
"Capturing image": "Bild wird aufgenommen",
10198
"Change text case": "Text-Groß-/Kleinschreibung ändern",
@@ -253,7 +250,6 @@
253250
"Download started": "Download gestartet",
254251
"Download SVG": "SVG herunterladen",
255252
"Drag files to move": "Ziehen Sie Dateien zum Verschieben",
256-
"Drop your Markdown files anywhere": "Legen Sie Ihre Markdown-Dateien irgendwo ab",
257253
"Duet Accord": "Duett-Akkord",
258254
"Duplicate": "Duplizieren",
259255
"Duplicate {{0}}": "Duplikat {{0}}",
@@ -303,7 +299,6 @@
303299
"Export document": "Dokument exportieren",
304300
"Export failed:": "Export fehlgeschlagen:",
305301
"Export PDF Options": "PDF-Optionen exportieren",
306-
"External Image (URL)": "Externes Bild (URL)",
307302
"Faceted Gear Wheel": "Facettiertes Zahnrad",
308303
"Failed to copy HTML:": "HTML konnte nicht kopiert werden:",
309304
"Failed to copy Markdown:": "Fehler beim Kopieren von Markdown:",
@@ -329,7 +324,6 @@
329324
"File created": "Datei erstellt",
330325
"File deleted": "Datei gelöscht",
331326
"File is already in that location.": "Die Datei befindet sich bereits an diesem Speicherort.",
332-
"File is too large (maximum 10MB supported).": "Datei ist zu groß (maximal 10 MB unterstützt).",
333327
"File moved to": "Datei verschoben nach",
334328
"File name": "Dateiname",
335329
"File options": "Dateioptionen",
@@ -364,7 +358,6 @@
364358
"Folder renamed": "Ordner umbenannt",
365359
"Folder renamed to": "Ordner umbenannt in",
366360
"folders": "-Ordner",
367-
"Folders stay one level deep inside a workspace.": "Ordner bleiben eine Ebene tief in einem Arbeitsbereich.",
368361
"Folk & Lyrics": "Folk & Texte",
369362
"for this block.": "für diesen Block.",
370363
"Forgot access key? Reset Secret Workspace": "Zugangsschlüssel vergessen? Geheimen Arbeitsbereich zurücksetzen",
@@ -410,11 +403,8 @@
410403
"HTML": "HTML",
411404
"HTML entities": "HTML-Entitäten",
412405
"HTML export failed:": "HTML-Export fehlgeschlagen:",
413-
"Image": "Bild",
414406
"Image (.png)": "Bild (.png)",
415-
"Image description": "Bildbeschreibung",
416407
"Image generation progress": "Fortschritt der Bildgenerierung",
417-
"Image URL": "Bild-URL",
418408
"Implement live preview with GitHub styling": "Live-Vorschau mit GitHub-Stil implementieren",
419409
"Import": "Importieren",
420410
"Import complete": "Import abgeschlossen",
@@ -435,7 +425,6 @@
435425
"Inline Code Blocks": "Inline-Codeblöcke",
436426
"Insert": "Einfügen",
437427
"Insert Diagram & More": "Diagramm und mehr einfügen",
438-
"Insert image": "Bild einfügen",
439428
"Insert link": "Link einfügen",
440429
"Insert reference": "Referenz einfügen",
441430
"Insert table": "Tabelle einfügen",
@@ -614,7 +603,6 @@
614603
"Please enter a GitHub URL.": "Please enter a GitHub URL.",
615604
"Please enter a valid GitHub URL.": "Please enter a valid GitHub URL.",
616605
"Please select at least one file to import.": "Bitte wählen Sie mindestens eine Datei zum Importieren aus.",
617-
"Please upload Markdown files (.md or .markdown)": "Bitte laden Sie Markdown Dateien hoch (.md oder .markdown)",
618606
"PNG": "PNG",
619607
"PNG export failed:": "PNG export failed:",
620608
"Polyphony Voices": "Polyphony Voices",
@@ -883,7 +871,6 @@
883871
"Unlock Secret Workspace": "Geheimen Arbeitsbereich freischalten",
884872
"Unlock workspace": "Arbeitsbereich entsperren",
885873
"Unlocking…": "Entsperren…",
886-
"Upload from Device": "Vom Gerät hochladen",
887874
"UPPERCASE": "GROSSBUCHSTABEN",
888875
"Use": "Verwendung",
889876
"Use at least 8 characters.": "Verwenden Sie mindestens 8 Zeichen.",
@@ -1009,8 +996,6 @@
1009996
"Incorrect access key or unreadable Secret Workspace data.": "Falscher Zugriffsschlüssel oder unlesbare Secret Workspace-Daten.",
1010997
"Live room disconnected": "Live-Raum nicht verbunden",
1011998
"Maximum document limit reached": "Maximale Dokumentengrenze erreicht",
1012-
"Mermaid diagram": "Meerjungfrau-Diagramm",
1013-
"Mermaid diagram actions": "Meerjungfrau-Diagrammaktionen",
1014999
"No documents match your search.": "Keine Dokumente entsprechen Ihrer Suche.",
10151000
"Open or create a document to use editing tools.": "Öffnen oder erstellen Sie ein Dokument, um Bearbeitungswerkzeuge zu verwenden.",
10161001
"Review item deleted.": "Bewertungselement gelöscht.",
@@ -1027,5 +1012,55 @@
10271012
"This share link has expired or does not exist.": "Dieser Freigabelink ist abgelaufen oder existiert nicht.",
10281013
"This shared document is read-only for you.": "Dieses freigegebene Dokument ist für Sie schreibgeschützt.",
10291014
"Your file is ready.": "Ihre Datei ist fertig.",
1030-
"Your files are ready.": "Ihre Dateien sind bereit."
1015+
"Your files are ready.": "Ihre Dateien sind bereit.",
1016+
"Collapse": "Reduzieren",
1017+
"converted to short links.": "in Kurzlinks umgewandelt.",
1018+
"Converting embedded images to short links.": "Eingebettete Bilder in Kurzlinks umwandeln.",
1019+
"Drop to import or insert": "Zum Importieren oder Einfügen ablegen",
1020+
"embedded image": "eingebettetes Bild",
1021+
"Embedded images could not be converted. Please try again.": "Eingebettete Bilder konnten nicht konvertiert werden. Bitte versuchen Sie es erneut.",
1022+
"expanded.": "erweitert.",
1023+
"Image conversion was cancelled because the document changed.": "Die Bildkonvertierung wurde abgebrochen, da sich das Dokument geändert hat.",
1024+
"MD": "MD",
1025+
"Open an editable Markdown file before inserting images.": "Öffnen Sie eine bearbeitbare Markdown-Datei, bevor Sie Bilder einfügen.",
1026+
"uploaded and inserted with short links.": "hochgeladen und mit Kurzlinks eingefügt.",
1027+
"\" aria-label=\"": "\" aria-label=\"",
1028+
"cancel": "abbrechen",
1029+
"Description": "Beschreibung",
1030+
"Dismiss notification": "Benachrichtigung verwerfen",
1031+
"External Media (URL)": "Externe Medien (URL)",
1032+
"Image, GIF, or video": "Bild, GIF oder Video",
1033+
"Images, GIFs, and videos are uploaded to create a short public link that expires after 90 days. Anyone with the media URL can view it until then. GIF limit: 5 MB; video limit: 10 MB.": "Bilder, GIFs und Videos werden hochgeladen, um einen kurzen öffentlichen Link zu erstellen, der nach 90 Tagen abläuft. Bis dahin kann jeder mit der Medien-URL es sehen. GIF-Limit: 5 MB; Videolimit: 10 MB.",
1034+
"Insert image, GIF, or video": "Fügen Sie ein Bild, GIF oder Video ein",
1035+
"Markdown files, images, GIFs, and videos are supported": "Markdown Dateien, Bilder, GIFs und Videos werden unterstützt",
1036+
"Media description": "Medienbeschreibung",
1037+
"media file": "Mediendatei",
1038+
"Media file": "Mediendatei",
1039+
"Media insertion cancelled": "Medieneinfügung abgebrochen",
1040+
"Media insertion was cancelled because the document changed.": "Das Einfügen des Mediums wurde abgebrochen, da sich das Dokument geändert hat.",
1041+
"Media upload cancelled.": "Medien-Upload abgebrochen.",
1042+
"Media upload complete": "Medien-Upload abgeschlossen",
1043+
"Media upload failed": "Medien-Upload fehlgeschlagen",
1044+
"Media upload progress": "Fortschritt des Medien-Uploads",
1045+
"Media URL": "Medien-URL",
1046+
"Notifications": "Benachrichtigungen",
1047+
"Preparing upload...": "Upload wird vorbereitet...",
1048+
"The document changed during upload.": "Das Dokument wurde während des Hochladens geändert.",
1049+
"The media file could not be inserted.": "Die Mediendatei konnte nicht eingefügt werden.",
1050+
"Upload Image, GIF, or Video": "Bild, GIF oder Video hochladen",
1051+
"Upload media?": "Medien hochladen?",
1052+
"Uploading media": "Medien werden hochgeladen",
1053+
"Uploading media file": "Mediendatei wird hochgeladen",
1054+
"Uploading media files": "Hochladen von Mediendateien",
1055+
"Choose a Markdown file (.md or .markdown).": "Wählen Sie eine Markdown-Datei (.md oder .markdown).",
1056+
"Choose an image, GIF, MP4, WebM, or Ogg video file.": "Wählen Sie ein Bild, eine GIF-, MP4-, WebM- oder Ogg-Videodatei.",
1057+
"Clipboard files must be an image, GIF, MP4, WebM, or Ogg video.": "Zwischenablagedateien müssen ein Bild, GIF, MP4, WebM oder Ogg-Video sein.",
1058+
"Dropped files must be Markdown, image, GIF, MP4, WebM, or Ogg files.": "Abgelegte Dateien müssen Markdown-, Bild-, GIF-, MP4-, WebM- oder Ogg-Dateien sein.",
1059+
"File not supported": "Datei wird nicht unterstützt",
1060+
"Some files were skipped. Choose Markdown files (.md or .markdown).": "Einige Dateien wurden übersprungen. Wählen Sie Markdown-Dateien (.md oder .markdown).",
1061+
"This file appears to be binary. Choose a Markdown file (.md or .markdown).": "Diese Datei scheint binär zu sein. Wählen Sie eine Markdown-Datei (.md oder .markdown).",
1062+
"This Markdown file is too large. The maximum supported size is 10 MB.": "Diese Markdown-Datei ist zu groß. Die maximal unterstützte Größe beträgt 10 MB.",
1063+
"This media file exceeds the supported limit: still images 25 MB before optimization, GIFs 5 MB, and videos 10 MB.": "Diese Mediendatei überschreitet den unterstützten Grenzwert: Standbilder 25 MB vor der Optimierung, GIFs 5 MB und Videos 10 MB.",
1064+
"Create a folder inside": "Erstellen Sie darin einen Ordner",
1065+
"Create a folder inside this workspace.": "Erstellen Sie einen Ordner in diesem Arbeitsbereich."
10311066
}

0 commit comments

Comments
 (0)