From c06fffc9941fdc32783ba9aec3dc12cac9a17758 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Mar 2026 04:43:58 +0000
Subject: [PATCH 1/3] Initial plan
From c857f3b5ac62a98b0afc45098aa8daf3d89b0ee9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Mar 2026 04:49:11 +0000
Subject: [PATCH 2/3] Add share button with URL-encoded markdown using pako
compression
Co-authored-by: ThisIs-Developer <109382325+ThisIs-Developer@users.noreply.github.com>
---
index.html | 9 +++++++
script.js | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+)
diff --git a/index.html b/index.html
index acdf8c0..73d4118 100644
--- a/index.html
+++ b/index.html
@@ -54,6 +54,7 @@
+
@@ -119,6 +120,10 @@
Markdown Viewer
Copy
+
+
@@ -191,6 +196,10 @@ Menu
Copy
+
+
diff --git a/script.js b/script.js
index 16ab0e2..fd6261c 100644
--- a/script.js
+++ b/script.js
@@ -57,6 +57,8 @@ document.addEventListener("DOMContentLoaded", function () {
const mobileExportPdf = document.getElementById("mobile-export-pdf");
const mobileCopyMarkdown = document.getElementById("mobile-copy-markdown");
const mobileThemeToggle = document.getElementById("mobile-theme-toggle");
+ const shareButton = document.getElementById("share-button");
+ const mobileShareButton = document.getElementById("mobile-share-button");
// Check dark mode preference first for proper initialization
const prefersDarkMode =
@@ -692,6 +694,7 @@ This is a fully client-side application. Your content never leaves your browser
mobileExportHtml.addEventListener("click", () => exportHtml.click());
mobileExportPdf.addEventListener("click", () => exportPdf.click());
mobileCopyMarkdown.addEventListener("click", () => copyMarkdownButton.click());
+ mobileShareButton.addEventListener("click", () => shareButton.click());
mobileThemeToggle.addEventListener("click", () => {
themeToggle.click();
mobileThemeToggle.innerHTML = themeToggle.innerHTML + " Toggle Dark Mode";
@@ -1526,6 +1529,81 @@ This is a fully client-side application. Your content never leaves your browser
}, 2000);
}
+ // ============================================
+ // Share via URL (pako compression + base64url)
+ // ============================================
+
+ const MAX_SHARE_URL_LENGTH = 32000;
+
+ function encodeMarkdownForShare(text) {
+ const compressed = pako.deflate(new TextEncoder().encode(text));
+ const chunkSize = 0x8000;
+ let binary = '';
+ for (let i = 0; i < compressed.length; i += chunkSize) {
+ binary += String.fromCharCode.apply(null, compressed.subarray(i, i + chunkSize));
+ }
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
+ }
+
+ function decodeMarkdownFromShare(encoded) {
+ const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');
+ const binary = atob(base64);
+ const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
+ return new TextDecoder().decode(pako.inflate(bytes));
+ }
+
+ shareButton.addEventListener("click", function () {
+ const markdownText = markdownEditor.value;
+ let encoded;
+ try {
+ encoded = encodeMarkdownForShare(markdownText);
+ } catch (e) {
+ console.error("Share encoding failed:", e);
+ alert("Failed to encode content for sharing: " + e.message);
+ return;
+ }
+
+ const shareUrl = window.location.origin + window.location.pathname + '#share=' + encoded;
+ if (shareUrl.length > MAX_SHARE_URL_LENGTH) {
+ alert("The document is too large to share via URL. Please reduce content size and try again.");
+ return;
+ }
+
+ window.location.hash = 'share=' + encoded;
+
+ const originalText = shareButton.innerHTML;
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard.writeText(shareUrl).then(() => {
+ shareButton.innerHTML = ' Copied!';
+ setTimeout(() => { shareButton.innerHTML = originalText; }, 2000);
+ }).catch(() => {
+ shareButton.innerHTML = ' Linked!';
+ setTimeout(() => { shareButton.innerHTML = originalText; }, 2000);
+ });
+ } else {
+ shareButton.innerHTML = ' Linked!';
+ setTimeout(() => { shareButton.innerHTML = originalText; }, 2000);
+ }
+ });
+
+ function loadFromShareHash() {
+ if (typeof pako === 'undefined') return;
+ const hash = window.location.hash;
+ if (!hash.startsWith('#share=')) return;
+ const encoded = hash.slice('#share='.length);
+ if (!encoded) return;
+ try {
+ const decoded = decodeMarkdownFromShare(encoded);
+ markdownEditor.value = decoded;
+ renderMarkdown();
+ } catch (e) {
+ console.error("Failed to load shared content:", e);
+ alert("The shared URL could not be decoded. It may be corrupted or incomplete.");
+ }
+ }
+
+ loadFromShareHash();
+
const dropEvents = ["dragenter", "dragover", "dragleave", "drop"];
dropEvents.forEach((eventName) => {
From 92c2fdf0094ceade0b1523c34576f95b387cec29 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Mar 2026 04:53:48 +0000
Subject: [PATCH 3/3] Fix invalid Docker tag on PR events by using static sha-
prefix
Co-authored-by: ThisIs-Developer <109382325+ThisIs-Developer@users.noreply.github.com>
---
.github/workflows/docker-publish.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml
index b489d2f..6a5177a 100644
--- a/.github/workflows/docker-publish.yml
+++ b/.github/workflows/docker-publish.yml
@@ -39,7 +39,7 @@ jobs:
tags: |
type=ref,event=branch
type=ref,event=pr
- type=sha,prefix={{branch}}-
+ type=sha,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image