From 5c938042a37ead547c7d6f041c2757da70e1d26b Mon Sep 17 00:00:00 2001 From: schmeeve Date: Wed, 23 Sep 2026 16:34:27 -0700 Subject: [PATCH] live preview --- browser-extension/.amo-upload-uuid | 1 + browser-extension/manifest.json | 2 +- static/app.css | 41 ++++++++++++++++++++++++++++++ static/app.js | 19 ++++++++++++-- 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 browser-extension/.amo-upload-uuid diff --git a/browser-extension/.amo-upload-uuid b/browser-extension/.amo-upload-uuid new file mode 100644 index 0000000..44a857e --- /dev/null +++ b/browser-extension/.amo-upload-uuid @@ -0,0 +1 @@ +{"uploadUuid":"4dae4288f9724a00b69f76b77b1da011","channel":"unlisted","xpiCrcHash":"77714bcdd59075c7a0167c21f97f0214fbc0e80e137095ac6f3ba232aa9d08b9"} \ No newline at end of file diff --git a/browser-extension/manifest.json b/browser-extension/manifest.json index 8d6de61..1a4c62c 100644 --- a/browser-extension/manifest.json +++ b/browser-extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "quickSnote", - "version": "1.0.0", + "version": "1.0.2", "description": "Quick-capture a note to snotes from any page, with the selected text and page link ready to use", "permissions": [ "storage" diff --git a/static/app.css b/static/app.css index d9217d4..325a377 100644 --- a/static/app.css +++ b/static/app.css @@ -326,6 +326,47 @@ body { .editor blockquote { border-left: 3px solid var(--secondary); margin: 0.5em 0; padding-left: 12px; color: var(--muted); } .editor a { color: var(--secondary); text-decoration: underline; cursor: pointer; } +.editor-split { + display: grid; + grid-template-columns: 1fr 1fr; + border: 1px solid var(--border); + border-top: none; + border-radius: 0 0 var(--radius) var(--radius); + overflow: hidden; +} +.editor-split .editor { + border: none; + border-right: 1px solid var(--border); + border-radius: 0; +} +.editor-split .preview { + background: var(--surface); + padding: 16px 20px; + min-height: 60vh; + overflow-y: auto; + line-height: 1.6; +} +.editor-split.preview-hidden { grid-template-columns: 1fr; } +.editor-split.preview-hidden .preview { display: none; } +.editor-split.preview-hidden .editor { border-right: none; } +.preview-toggle.active { color: var(--primary); } + +.preview h1, .preview h2, .preview h3, .preview h4 { margin: 0.5em 0 0.25em; color: var(--secondary); } +.preview h1 { font-size: 1.6em; } +.preview h2 { font-size: 1.35em; } +.preview h3 { font-size: 1.15em; } +.preview p { margin: 0.4em 0; } +.preview ul, .preview ol { padding-left: 1.5em; margin: 0.4em 0; } +.preview pre { background: var(--code-bg); color: var(--code-fg); padding: 12px; border-radius: 8px; overflow-x: auto; } +.preview code { background: color-mix(in srgb, var(--border) 55%, transparent); padding: 1px 4px; border-radius: 4px; font-size: 0.9em; } +.preview pre code { background: none; padding: 0; } +.preview blockquote { border-left: 3px solid var(--secondary); margin: 0.5em 0; padding-left: 12px; color: var(--muted); } +.preview a { color: var(--secondary); text-decoration: underline; } +.preview hr { border: none; border-top: 1px solid var(--border); margin: 1em 0; } +.preview img { max-width: 100%; } +.preview table { border-collapse: collapse; } +.preview th, .preview td { border: 1px solid var(--border); padding: 4px 8px; } + .status { margin-top: 10px; color: var(--muted); font-size: 13px; min-height: 20px; } .editor-hint { margin-top: 12px; padding: 10px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); font-size: 13px; color: var(--muted); line-height: 1.6; } .editor-hint p { margin: 0.25em 0; } diff --git a/static/app.js b/static/app.js index 80856e1..b52ff79 100644 --- a/static/app.js +++ b/static/app.js @@ -496,6 +496,9 @@ function renderEditor(body, owner) { sep(), toolbarBtn("—", "horizontalRule"), ]); const editorArea = el("div", { class: "editor" }); + const previewArea = el("div", { class: "preview" }); + const split = el("div", { class: "editor-split" }, [editorArea, previewArea]); + const previewBtn = el("button", { class: "btn ghost preview-toggle active", text: "Preview", title: "Toggle live preview", onclick: () => { split.classList.toggle("preview-hidden"); previewBtn.classList.toggle("active"); } }); const status = el("div", { class: "status", text: "" }); const hint = el("div", { class: "editor-hint" }, [ el("p", { html: 'Tags: type #tag anywhere in your note to add a tag.' }), @@ -508,9 +511,9 @@ function renderEditor(body, owner) { const attach = el("button", { class: "btn", text: "Attach", onclick: () => fileInput.click() }); const wrap = el("div", { class: "editor-wrap" }, [ - el("div", { class: "editor-topbar" }, [back, spaceSel, el("div", { class: "spacer" }), attach, hist, del, commonLabel, save]), + el("div", { class: "editor-topbar" }, [back, spaceSel, el("div", { class: "spacer" }), attach, hist, del, commonLabel, previewBtn, save]), toolbar, - editorArea, + split, hint, status, ]); @@ -523,6 +526,18 @@ function renderEditor(body, owner) { content: marked.parse(body), autofocus: true, }); + + function updatePreview() { + const md = turndownService.turndown(state.editor.getHTML()); + previewArea.innerHTML = marked.parse(md); + } + state.editor.on("update", updatePreview); + updatePreview(); + + previewArea.addEventListener("click", (e) => { + const a = e.target.closest("a"); + if (a) e.preventDefault(); + }); } function sep() { return el("span", { class: "sep" }); }