still snoting

This commit is contained in:
2026-09-25 14:24:33 -07:00
parent 1fc3cc0e74
commit 54da169fe5
4 changed files with 52 additions and 10 deletions

View File

@@ -11,7 +11,7 @@
</div>
<textarea id="note" placeholder="Type a note…" spellcheck="false"></textarea>
<div class="actions">
<button id="capture-page" title="Insert page title + link and attach a full-page screenshot" type="button">⤴ Page</button>
<button id="capture-page" title="Bookmark this page: insert title + link, tag #bookmark, and attach a full-page screenshot" type="button">⤴ Bookmark</button>
<div class="spacer"></div>
<button id="save" class="primary" type="button">Save</button>
</div>

View File

@@ -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);

View File

@@ -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;

View File

@@ -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(/<img[^>]*>/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: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>' }),
]);
}
function toolbarBtn(label, action) {
return el("button", { class: "tool-btn", text: label, onclick: () => runToolbar(action) });
}