|
|
|
@@ -200,7 +200,7 @@ function header() {
|
|
|
|
el("span", {}), el("span", {}), el("span", {}),
|
|
|
|
el("span", {}), el("span", {}), el("span", {}),
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
return el("header", { class: "topbar" }, [
|
|
|
|
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" }),
|
|
|
|
el("img", { src: "/static/snotes-logo.png", class: "brand-logo", alt: "snotes" }),
|
|
|
|
]),
|
|
|
|
]),
|
|
|
|
burger,
|
|
|
|
burger,
|
|
|
|
@@ -214,7 +214,7 @@ function showHelp() {
|
|
|
|
root.innerHTML = "";
|
|
|
|
root.innerHTML = "";
|
|
|
|
state.editor?.destroy(); state.editor = null;
|
|
|
|
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" }, [
|
|
|
|
const wrap = el("div", { class: "editor-wrap" }, [
|
|
|
|
el("div", { class: "editor-topbar" }, [back]),
|
|
|
|
el("div", { class: "editor-topbar" }, [back]),
|
|
|
|
el("div", { class: "help-card" }, [
|
|
|
|
el("div", { class: "help-card" }, [
|
|
|
|
@@ -254,7 +254,7 @@ function showTools() {
|
|
|
|
root.innerHTML = "";
|
|
|
|
root.innerHTML = "";
|
|
|
|
state.editor?.destroy(); state.editor = null;
|
|
|
|
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 extStatus = el("div", { class: "muted", text: "" });
|
|
|
|
const installBtn = el("button", { class: "btn primary", text: "Install Browser Extension" });
|
|
|
|
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" }));
|
|
|
|
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)}`));
|
|
|
|
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") }));
|
|
|
|
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" }, [
|
|
|
|
const bodyEl = el("div", { class: "note-body" }, [
|
|
|
|
el("div", { class: "note-title", text: n.title || "Untitled" }),
|
|
|
|
el("div", { class: "note-title", text: n.title || "Untitled" }),
|
|
|
|
meta,
|
|
|
|
meta,
|
|
|
|
el("div", { class: "note-tags", text: tags }),
|
|
|
|
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) }, [
|
|
|
|
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,
|
|
|
|
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 results = await api("GET", "/api/search?q=" + encodeURIComponent(q));
|
|
|
|
const box = document.getElementById("search-results");
|
|
|
|
const box = document.getElementById("search-results");
|
|
|
|
box.innerHTML = "";
|
|
|
|
box.innerHTML = "";
|
|
|
|
box.appendChild(el("h2", { text: `Results for "${q}"` }));
|
|
|
|
box.appendChild(searchHeader(q));
|
|
|
|
box.appendChild(noteList(results));
|
|
|
|
box.appendChild(noteList(results));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -451,10 +453,23 @@ async function searchFor(q) {
|
|
|
|
const results = await api("GET", "/api/search?q=" + encodeURIComponent(q));
|
|
|
|
const results = await api("GET", "/api/search?q=" + encodeURIComponent(q));
|
|
|
|
const box = document.getElementById("search-results");
|
|
|
|
const box = document.getElementById("search-results");
|
|
|
|
box.innerHTML = "";
|
|
|
|
box.innerHTML = "";
|
|
|
|
box.appendChild(el("h2", { text: `Results for "${q}"` }));
|
|
|
|
box.appendChild(searchHeader(q));
|
|
|
|
box.appendChild(noteList(results));
|
|
|
|
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) {
|
|
|
|
function fmtDate(iso) {
|
|
|
|
if (!iso) return "";
|
|
|
|
if (!iso) return "";
|
|
|
|
const d = new Date(iso.replace(" ", "T") + "Z");
|
|
|
|
const d = new Date(iso.replace(" ", "T") + "Z");
|
|
|
|
@@ -494,7 +509,7 @@ function renderEditor(body, owner) {
|
|
|
|
state.editor?.destroy();
|
|
|
|
state.editor?.destroy();
|
|
|
|
|
|
|
|
|
|
|
|
const isNew = !state.noteId;
|
|
|
|
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 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;
|
|
|
|
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 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) {
|
|
|
|
function toolbarBtn(label, action) {
|
|
|
|
return el("button", { class: "tool-btn", text: label, onclick: () => runToolbar(action) });
|
|
|
|
return el("button", { class: "tool-btn", text: label, onclick: () => runToolbar(action) });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|