Menu
Public repository / 38be73dca20817617deadd99becbf1502c224f02
AkurAI-Notes / site/frontend/notes-app.js
Latest change 9846363ea7fea56c5079985945447933709e6726 - fix: restore Notes app SSR routes by Claude Code
(function () {
"use strict";
function esc(value) {
return String(value ?? "").replace(/[&<>"]/g, function (m) {
return { "&": "&", "<": "<", ">": ">", '"': """ }[m];
});
}
async function jsonFetch(url) {
const res = await fetch(url, {
credentials: "same-origin",
headers: { accept: "application/json" },
});
const text = await res.text();
let data = null;
if (text) {
try {
data = JSON.parse(text);
} catch (err) {
throw new Error("The server returned invalid JSON");
}
}
if (data && data.error === "unauthorized") {
window.location.href = "/auth/login";
throw new Error("Redirecting to sign in");
}
if (!res.ok) {
throw new Error((data && data.error) || `HTTP ${res.status}`);
}
return data;
}
function renderNoteCard(note) {
const title = note.title || "Untitled";
const body = note.snippet || note.body || "";
return (
'<article class="note-card">' +
"<h3>" + esc(title) + "</h3>" +
'<p class="note-preview">' + esc(body).slice(0, 360) + "</p>" +
"</article>"
);
}
function renderEmpty(target, message) {
target.innerHTML = '<p class="empty-state">' + esc(message) + "</p>";
}
async function initNotesPage() {
const notebooksEl = document.getElementById("notebook-list");
const content = document.getElementById("notes-content");
if (!notebooksEl || !content) return;
try {
const me = await jsonFetch("/api/me");
if (!me || !me.authenticated) {
window.location.href = "/auth/login";
return;
}
const [notebooks, notes] = await Promise.all([
jsonFetch("/api/notebooks"),
jsonFetch("/api/notes"),
]);
const notebookList = Array.isArray(notebooks) ? notebooks : [];
const noteList = Array.isArray(notes) ? notes : [];
notebooksEl.innerHTML = notebookList.length
? notebookList
.map(function (nb) {
return '<li class="notebook-item">' + esc(nb.name || "Untitled") + "</li>";
})
.join("")
: '<li class="notebook-item muted">No notebooks</li>';
if (!noteList.length) {
renderEmpty(content, "No notes found");
return;
}
content.innerHTML = '<div class="note-grid">' + noteList.map(renderNoteCard).join("") + "</div>";
} catch (err) {
if (String(err.message).includes("Redirecting")) return;
renderEmpty(content, "Could not load notes: " + err.message);
}
}
async function runSearch(query) {
const resultsEl = document.getElementById("notes-search-results");
const metaEl = document.getElementById("notes-search-meta");
if (!resultsEl || !metaEl) return;
const q = query.trim();
if (!q) {
metaEl.textContent = "";
renderEmpty(resultsEl, "Type a search query");
return;
}
metaEl.textContent = "Searching";
try {
const data = await jsonFetch("/api/search?q=" + encodeURIComponent(q));
const results = Array.isArray(data && data.results) ? data.results : [];
metaEl.textContent = results.length + " result" + (results.length === 1 ? "" : "s") + " ยท " + (data.mode || "search");
if (!results.length) {
renderEmpty(resultsEl, "No matching notes");
return;
}
resultsEl.innerHTML = results.map(renderNoteCard).join("");
} catch (err) {
if (String(err.message).includes("Redirecting")) return;
metaEl.textContent = "";
renderEmpty(resultsEl, "Search failed: " + err.message);
}
}
function initSearchPage() {
const form = document.getElementById("notes-search-form");
const input = document.getElementById("notes-search-input");
const params = new URLSearchParams(window.location.search);
if (!form || !input) return;
input.value = params.get("q") || "";
form.addEventListener("submit", function (event) {
event.preventDefault();
const q = input.value.trim();
const next = q ? "/app/search?q=" + encodeURIComponent(q) : "/app/search";
window.history.replaceState(null, "", next);
runSearch(q);
});
runSearch(input.value);
}
async function initSettingsPage() {
const email = document.getElementById("settings-email");
if (!email) return;
try {
const me = await jsonFetch("/api/me");
if (!me || !me.authenticated) {
window.location.href = "/auth/login";
return;
}
email.textContent = me.email || me.sub || "Authenticated";
} catch (err) {
if (String(err.message).includes("Redirecting")) return;
email.textContent = "Session unavailable";
}
}
window.NotesApp = { initNotesPage, initSearchPage, initSettingsPage };
})();