Skip to content
Open
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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ COPY workspace-storage.js /usr/share/nginx/html/
COPY visual-settings-adapters.js /usr/share/nginx/html/
COPY visual-settings-store.js /usr/share/nginx/html/
COPY script.js /usr/share/nginx/html/
COPY sharing-crypto.js sharing-media.js sharing-live.js /usr/share/nginx/html/
COPY styles.css /usr/share/nginx/html/
COPY sw.js /usr/share/nginx/html/
COPY RELEASE_NOTES /usr/share/nginx/html/
Expand Down Expand Up @@ -39,6 +40,9 @@ RUN echo 'server { \
} \
\
# Cache static assets \
location ~* \.mjs$ { \
default_type application/javascript; \
} \
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { \
expires 1y; \
add_header Cache-Control "public, immutable"; \
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

Markdown Viewer is an open source, local-first workspace for developers, writers, students, researchers, and anyone working with `.md` or `.markdown` files. Go beyond plain text. Organize multiple documents, review with anchored comments without changing the Markdown, and render diagrams, maps, charts, math, 3D models, and music—all in one focused workspace.

Turn a document into a Share Snapshot link for quick handoffs, or start access-controlled Live Share for real-time co-editing, live cursors, anchored comments, and threaded replies. Everyday editing stays on your device. No account is required, and the application includes no ads, analytics, telemetry, or subscriptions.
Turn a document into an encrypted Share Snapshot link for quick handoffs, or start encrypted Live Share for real-time co-editing, live cursors, anchored comments, and threaded replies. Everyday editing stays on your device. No account is required, and the application includes no ads, analytics, telemetry, or subscriptions.

<p align="center">
<img src="https://github.com/user-attachments/assets/5a0d6fda-96f0-4baf-bf7a-0ffbe5119eab" alt="Application UI" width="90%" />
Expand All @@ -74,7 +74,7 @@ Turn a document into a Share Snapshot link for quick handoffs, or start access-c

- **Import and export:** open local files or GitHub content from branches, tags, commit SHAs, and optionally private repositories; export Markdown, standalone HTML, PNG, Standard PDF/Save as PDF, or Rendered PDF with remembered Light or Dark appearance and complete rich-content preparation for PDF and PNG.

- **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.
- **Optional sharing:** create an encrypted Share Snapshot with View only or Can edit access, or start an encrypted Live Share room with role-based signatures. Keep complete links private: they carry decryption keys. Existing shares retain their original expiry.

<p align="center">
<img src="https://github.com/user-attachments/assets/0b2080e8-6ba8-4dac-a58a-d043fadeeb61" alt="Live share" width="90%" />
Expand Down Expand Up @@ -115,12 +115,12 @@ Markdown Viewer is local-first, not network-free. The following table shows the
| Web libraries and uncached renderer dependencies | CDN requests in the web/PWA build |
| 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 |
| Consented image, GIF, and video insertion | Encrypted Cloudflare media storage for 90 days |
| Large Share Snapshot | Cloudflare KV for 90 days |
| Live Share | WebSocket relay through a Cloudflare Durable Object; document content is not persisted server-side |
| External images, media, links, and map tiles | The referenced external host |

Share Snapshot and Live Share URLs are bearer links. Anyone who obtains a valid link and capability can use the access it grants. Live Share is not end-to-end encrypted. See [Privacy and Security](wiki/Privacy-and-Security.md) before using network features with sensitive content.
Share Snapshot and Live Share URLs are bearer links. Anyone who obtains a valid link and capability can use the access it grants. New snapshots, managed media, and live rooms use client-side encryption; complete links contain decryption keys. See [Privacy and Security](wiki/Privacy-and-Security.md) before using network features with sensitive content.

## Visual Renderer Summary

Expand Down Expand Up @@ -164,7 +164,7 @@ Remote renderer services receive the source of the diagram they render. Do not s
- A local Markdown file larger than 10 MB is rejected.
- The GitHub credential vault stores up to 50 named PAT entries; each token name is limited to 60 characters.
- 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.
- Stored Share Snapshot payloads are limited to 8 MiB before encryption and expire after 90 days.
- Live Share allows up to 64 WebSocket participants and 8 MB per live message.
- STL source is limited to 2 MiB and rendered geometry to 300,000 vertices.
- The desktop vault retains up to 20 recent history copies per document.
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/bg.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Шифровано споделяне. Пазете цялата връзка в тайна; тя съдържа ключа за дешифриране.",
"Delete snapshot": "Изтриване на моментната снимка",
"Snapshot deleted.": "Моментната снимка е изтрита.",
"Connected to encrypted live room": "Свързано с шифрована стая на живо",
"Linking folder": "Свързване на папка",
"Scanning folder…": "Сканиране на папката…",
"Reading files…": "Четене на файлове…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/de.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Verschlüsselte Freigabe. Halten Sie den vollständigen Link geheim; er enthält den Entschlüsselungsschlüssel.",
"Delete snapshot": "Momentaufnahme löschen",
"Snapshot deleted.": "Momentaufnahme gelöscht.",
"Connected to encrypted live room": "Mit verschlüsseltem Live-Raum verbunden",
"Linking folder": "Ordner wird verknüpft",
"Scanning folder…": "Ordner wird durchsucht…",
"Reading files…": "Dateien werden gelesen…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Encrypted sharing. Keep the complete link private; it includes the decryption key.",
"Delete snapshot": "Delete snapshot",
"Snapshot deleted.": "Snapshot deleted.",
"Connected to encrypted live room": "Connected to encrypted live room",
"Linking folder": "Linking folder",
"Scanning folder…": "Scanning folder…",
"Reading files…": "Reading files…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/es.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Uso compartido cifrado. Mantén privado el enlace completo; incluye la clave de descifrado.",
"Delete snapshot": "Eliminar instantánea",
"Snapshot deleted.": "Instantánea eliminada.",
"Connected to encrypted live room": "Conectado a la sala en vivo cifrada",
"Linking folder": "Vinculando carpeta",
"Scanning folder…": "Explorando carpeta…",
"Reading files…": "Leyendo archivos…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/fr.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Partage chiffré. Gardez le lien complet privé ; il contient la clé de déchiffrement.",
"Delete snapshot": "Supprimer l’instantané",
"Snapshot deleted.": "Instantané supprimé.",
"Connected to encrypted live room": "Connecté à la salle en direct chiffrée",
"Linking folder": "Liaison du dossier",
"Scanning folder…": "Analyse du dossier…",
"Reading files…": "Lecture des fichiers…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/it.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Condivisione crittografata. Mantieni privato il link completo: contiene la chiave di decrittazione.",
"Delete snapshot": "Elimina istantanea",
"Snapshot deleted.": "Istantanea eliminata.",
"Connected to encrypted live room": "Connesso alla stanza live crittografata",
"Linking folder": "Collegamento della cartella",
"Scanning folder…": "Scansione della cartella…",
"Reading files…": "Lettura dei file…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/ja.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "暗号化された共有です。完全なリンクには復号キーが含まれるため、秘密にしてください。",
"Delete snapshot": "スナップショットを削除",
"Snapshot deleted.": "スナップショットを削除しました。",
"Connected to encrypted live room": "暗号化されたライブルームに接続しました",
"Linking folder": "フォルダーをリンク中",
"Scanning folder…": "フォルダーをスキャン中…",
"Reading files…": "ファイルを読み込み中…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/ko.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "암호화된 공유입니다. 전체 링크에는 복호화 키가 포함되어 있으므로 비공개로 유지하세요.",
"Delete snapshot": "스냅샷 삭제",
"Snapshot deleted.": "스냅샷이 삭제되었습니다.",
"Connected to encrypted live room": "암호화된 라이브 룸에 연결됨",
"Linking folder": "폴더 연결 중",
"Scanning folder…": "폴더 검색 중…",
"Reading files…": "파일 읽는 중…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/pl.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Udostępnianie szyfrowane. Zachowaj pełny link w tajemnicy; zawiera klucz odszyfrowywania.",
"Delete snapshot": "Usuń migawkę",
"Snapshot deleted.": "Migawka usunięta.",
"Connected to encrypted live room": "Połączono z szyfrowanym pokojem na żywo",
"Linking folder": "Łączenie folderu",
"Scanning folder…": "Skanowanie folderu…",
"Reading files…": "Odczytywanie plików…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/pt.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Partilha encriptada. Mantenha a ligação completa privada; inclui a chave de desencriptação.",
"Delete snapshot": "Eliminar instantâneo",
"Snapshot deleted.": "Instantâneo eliminado.",
"Connected to encrypted live room": "Ligado à sala ao vivo encriptada",
"Linking folder": "Vinculando pasta",
"Scanning folder…": "Verificando pasta…",
"Reading files…": "Lendo arquivos…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Зашифрованный общий доступ. Храните полную ссылку в тайне: она содержит ключ расшифровки.",
"Delete snapshot": "Удалить снимок",
"Snapshot deleted.": "Снимок удалён.",
"Connected to encrypted live room": "Подключено к зашифрованной комнате",
"Linking folder": "Подключение папки",
"Scanning folder…": "Сканирование папки…",
"Reading files…": "Чтение файлов…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/tr.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Şifreli paylaşım. Şifre çözme anahtarını içerdiğinden bağlantının tamamını gizli tutun.",
"Delete snapshot": "Anlık görüntüyü sil",
"Snapshot deleted.": "Anlık görüntü silindi.",
"Connected to encrypted live room": "Şifreli canlı odaya bağlanıldı",
"Linking folder": "Klasör bağlanıyor",
"Scanning folder…": "Klasör taranıyor…",
"Reading files…": "Dosyalar okunuyor…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/tw.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "加密分享。請將完整連結保密,其中包含解密金鑰。",
"Delete snapshot": "刪除快照",
"Snapshot deleted.": "快照已刪除。",
"Connected to encrypted live room": "已連線至加密的即時協作房間",
"Linking folder": "正在連結資料夾",
"Scanning folder…": "正在掃描資料夾…",
"Reading files…": "正在讀取檔案…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/uk.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "Зашифрований спільний доступ. Зберігайте повне посилання в таємниці: воно містить ключ розшифрування.",
"Delete snapshot": "Видалити знімок",
"Snapshot deleted.": "Знімок видалено.",
"Connected to encrypted live room": "Підключено до зашифрованої кімнати",
"Linking folder": "Підключення папки",
"Scanning folder…": "Сканування папки…",
"Reading files…": "Читання файлів…",
Expand Down
4 changes: 4 additions & 0 deletions assets/i18n/zh.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Encrypted sharing. Keep the complete link private; it includes the decryption key.": "加密分享。请将完整链接保密,其中包含解密密钥。",
"Delete snapshot": "删除快照",
"Snapshot deleted.": "快照已删除。",
"Connected to encrypted live room": "已连接到加密的实时协作房间",
"Linking folder": "正在链接文件夹",
"Scanning folder…": "正在扫描文件夹…",
"Reading files…": "正在读取文件…",
Expand Down
47 changes: 47 additions & 0 deletions assets/yjs.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Yjs
The MIT License (MIT)

Copyright (c) 2023
- Kevin Jahns <kevin.jahns@protonmail.com>.
- Chair of Computer Science 5 (Databases & Information Systems), RWTH Aachen University, Germany

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

lib0
The MIT License (MIT)

Copyright (c) 2019 Kevin Jahns <kevin.jahns@protonmail.com>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading