From 54da169fe50ab9e8095141909b5483bf87fe9e00 Mon Sep 17 00:00:00 2001 From: schmeeve Date: Fri, 25 Sep 2026 14:24:33 -0700 Subject: [PATCH] still snoting --- browser-extension/popup.html | 2 +- browser-extension/popup.js | 2 +- static/app.css | 23 ++++++++++++++++++++++- static/app.js | 35 ++++++++++++++++++++++++++++------- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/browser-extension/popup.html b/browser-extension/popup.html index d0660de..97c73d6 100644 --- a/browser-extension/popup.html +++ b/browser-extension/popup.html @@ -11,7 +11,7 @@
- +
diff --git a/browser-extension/popup.js b/browser-extension/popup.js index e0d725e..31ea835 100644 --- a/browser-extension/popup.js +++ b/browser-extension/popup.js @@ -65,7 +65,7 @@ var link = '[' + (title || url) + '](' + (url || '') + ')'; var v = noteEl.value; if (v && !/\n$/.test(v)) v += '\n'; - noteEl.value = v + link + '\n'; + noteEl.value = v + link + ' #bookmark\n'; captureBtn.disabled = true; showStatus('Capturing full page…', true); diff --git a/static/app.css b/static/app.css index 04f16c8..56ce895 100644 --- a/static/app.css +++ b/static/app.css @@ -212,7 +212,7 @@ body { z-index: 10; } -.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 18px; } +.brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 18px; cursor: pointer; } .brand-logo { height: 65px; width: auto; object-fit: contain; } .search { @@ -267,6 +267,27 @@ body { .btn.danger { color: var(--danger); border-color: var(--danger); } .btn.ghost { background: transparent; border-color: transparent; } +.back-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + flex-shrink: 0; + border: 1px solid var(--border); + border-radius: 50%; + background: var(--surface); + color: var(--text); + cursor: pointer; + padding: 0; +} +.back-btn:hover { background: var(--bg-hover); border-color: var(--primary); } +.back-icon { display: inline-flex; } +.back-icon svg { width: 18px; height: 18px; } + +.results-head { display: flex; align-items: center; gap: 10px; } +.results-head h2 { margin: 0; font-size: 20px; } + .layout { display: grid; grid-template-columns: 1fr 300px; diff --git a/static/app.js b/static/app.js index bca8ec8..ff8f455 100644 --- a/static/app.js +++ b/static/app.js @@ -200,7 +200,7 @@ function header() { el("span", {}), el("span", {}), el("span", {}), ]); return el("header", { class: "topbar" }, [ - el("div", { class: "brand" }, [ + el("div", { class: "brand", onclick: showHome, title: "Home", role: "button" }, [ el("img", { src: "/static/snotes-logo.png", class: "brand-logo", alt: "snotes" }), ]), burger, @@ -214,7 +214,7 @@ function showHelp() { root.innerHTML = ""; state.editor?.destroy(); state.editor = null; - const back = el("button", { class: "btn ghost", text: "← Back", onclick: showHome }); + const back = backButton(showHome); const wrap = el("div", { class: "editor-wrap" }, [ el("div", { class: "editor-topbar" }, [back]), el("div", { class: "help-card" }, [ @@ -254,7 +254,7 @@ function showTools() { root.innerHTML = ""; state.editor?.destroy(); state.editor = null; - const back = el("button", { class: "btn ghost", text: "← Back", onclick: showHome }); + const back = backButton(showHome); const extStatus = el("div", { class: "muted", text: "" }); const installBtn = el("button", { class: "btn primary", text: "Install Browser Extension" }); @@ -422,11 +422,13 @@ function noteList(notes) { if (isCommon) meta.appendChild(el("span", { class: "common-badge", text: "common" })); meta.appendChild(document.createTextNode(`${n.username} · edited ${relTime(n.updated_at)} · created ${fmtDate(n.created_at)}`)); if (n.attachments) meta.appendChild(el("span", { class: "attach-count", text: n.attachments + " attachment" + (n.attachments === 1 ? "" : "s") })); + let snippetHtml = n.snippet ? marked.parse(n.snippet) : ""; + if (n.image) snippetHtml = snippetHtml.replace(/]*>/g, "").trim(); const bodyEl = el("div", { class: "note-body" }, [ el("div", { class: "note-title", text: n.title || "Untitled" }), meta, el("div", { class: "note-tags", text: tags }), - n.snippet ? el("div", { class: "note-snippet", html: marked.parse(n.snippet) }) : null, + snippetHtml ? el("div", { class: "note-snippet", html: snippetHtml }) : null, ]); ul.appendChild(el("li", { class: isCommon ? "note-item note-common" : "note-item", onclick: () => openNote(n.id) }, [ n.image ? el("img", { class: "note-banner", src: n.image, alt: "", loading: "lazy" }) : null, @@ -442,7 +444,7 @@ async function onSearch(e) { const results = await api("GET", "/api/search?q=" + encodeURIComponent(q)); const box = document.getElementById("search-results"); box.innerHTML = ""; - box.appendChild(el("h2", { text: `Results for "${q}"` })); + box.appendChild(searchHeader(q)); box.appendChild(noteList(results)); } @@ -451,10 +453,23 @@ async function searchFor(q) { const results = await api("GET", "/api/search?q=" + encodeURIComponent(q)); const box = document.getElementById("search-results"); box.innerHTML = ""; - box.appendChild(el("h2", { text: `Results for "${q}"` })); + box.appendChild(searchHeader(q)); box.appendChild(noteList(results)); } +function searchHeader(q) { + return el("div", { class: "results-head" }, [ + backButton(clearSearch), + el("h2", { text: `Results for "${q}"` }), + ]); +} + +async function clearSearch() { + document.getElementById("search").value = ""; + document.getElementById("search-results").innerHTML = ""; + await loadRecent(); +} + function fmtDate(iso) { if (!iso) return ""; const d = new Date(iso.replace(" ", "T") + "Z"); @@ -494,7 +509,7 @@ function renderEditor(body, owner) { state.editor?.destroy(); const isNew = !state.noteId; - const back = el("button", { class: "btn ghost", text: "← Back", onclick: exitEditor }); + const back = backButton(exitEditor); const del = state.noteId ? el("button", { class: "btn danger", text: "Delete", onclick: deleteNote }) : null; const hist = state.noteId ? el("button", { class: "btn ghost", text: "History", onclick: showHistory }) : null; @@ -570,6 +585,12 @@ function renderEditor(body, owner) { function sep() { return el("span", { class: "sep" }); } +function backButton(onclick) { + return el("button", { class: "back-btn", title: "Back", "aria-label": "Back", onclick }, [ + el("span", { class: "back-icon", html: '' }), + ]); +} + function toolbarBtn(label, action) { return el("button", { class: "tool-btn", text: label, onclick: () => runToolbar(action) }); }