recent comments
All checks were successful
Build Org Website / build (push) Successful in 50s

This commit is contained in:
2026-05-10 22:32:41 +01:00
parent 8f8a5dddf9
commit b9cb71a310
5 changed files with 721 additions and 0 deletions

View File

@@ -69,6 +69,10 @@
.replace(/"/g, """);
}
function escAttr(str) {
return escHtml(str).replace(/'/g, "'");
}
function normaliseHref(href, prefix) {
if (!href || href.startsWith("http") || href.startsWith("#")) return null;
if (href.startsWith("/")) return href;
@@ -132,6 +136,129 @@
}
}
function commentSlug(comment) {
return comment.pageSlug || comment.page_slug || "";
}
function commentDate(comment) {
return comment.created_at || comment.createdAt || "";
}
function formatCommentDate(value) {
const date = new Date(value);
if (Number.isNaN(date.getTime())) return "";
return new Intl.DateTimeFormat(undefined, {
month: "short",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
}).format(date);
}
function commentExcerpt(content) {
const text = String(content || "").replace(/\s+/g, " ").trim();
if (text.length <= 150) return text;
return text.slice(0, 147).trimEnd() + "...";
}
function renderRecentComments(comments, pageMap) {
const ul = document.getElementById("db-feed-comments");
if (!ul) return;
if (!comments.length) {
ul.innerHTML = (
`<li class="db-comment-feed__item">` +
`<span class="db-feed__dot"></span>` +
`<div class="db-comment-feed__body">` +
`<span class="db-comment-feed__empty">No comments yet.</span>` +
`</div>` +
`</li>`
);
return;
}
ul.innerHTML = comments.map((comment) => {
const slug = commentSlug(comment);
const page = pageMap.get(slug);
const title = page?.title || slug || "Unknown page";
const href = page?.url ? page.url + "#comments" : null;
const author = comment.author || "Anonymous";
const date = formatCommentDate(commentDate(comment));
const pageLink = href
? `<a class="db-comment-feed__page" href="${escAttr(href)}">${escHtml(title)}</a>`
: `<span class="db-comment-feed__page">${escHtml(title)}</span>`;
return (
`<li class="db-comment-feed__item">` +
`<span class="db-feed__dot"></span>` +
`<div class="db-comment-feed__body">` +
`<div class="db-comment-feed__top">` +
`<strong>${escHtml(author)}</strong>` +
`<span>on</span>` +
pageLink +
(date ? `<time datetime="${escAttr(commentDate(comment))}">${escHtml(date)}</time>` : "") +
`</div>` +
`<p>${escHtml(commentExcerpt(comment.content))}</p>` +
`</div>` +
`</li>`
);
}).join("");
}
async function loadCommentPageMap() {
try {
const resp = await fetch("/assets/content/comment-pages.json", { credentials: "same-origin" });
if (!resp.ok) return new Map();
const pages = await resp.json();
return new Map(
pages
.filter((page) => page.slug && page.url)
.map((page) => [page.slug, page])
);
} catch (_) {
return new Map();
}
}
async function loadRecentComments() {
const ul = document.getElementById("db-feed-comments");
if (!ul) return;
const renderUnavailable = () => {
ul.innerHTML = (
`<li class="db-comment-feed__item">` +
`<span class="db-feed__dot"></span>` +
`<div class="db-comment-feed__body">` +
`<span class="db-comment-feed__empty">Recent comments are unavailable.</span>` +
`</div>` +
`</li>`
);
};
try {
const [pageMap, resp] = await Promise.all([
loadCommentPageMap(),
fetch("/api/comments", { credentials: "same-origin" }),
]);
if (!resp.ok) {
renderUnavailable();
return;
}
const comments = await resp.json();
const recent = comments
.filter((comment) => commentDate(comment))
.sort((a, b) => new Date(commentDate(b)) - new Date(commentDate(a)))
.slice(0, 10);
renderRecentComments(recent, pageMap);
} catch (_) {
renderUnavailable();
}
}
function initCommandFilter() {
const input = document.getElementById("db-command-search");
const nav = document.getElementById("db-quicknav");
@@ -169,6 +296,7 @@
loadFeed("/blogs/blogs-list.html", "db-feed-blogs", 6, "/blogs");
loadFeed("/posts/posts-list.html", "db-feed-posts", 6, "/posts");
loadFeed("/recently-updated.html", "db-feed-recent", 6, "");
loadRecentComments();
}
if (document.readyState === "loading") {