removing author and cleaning js / css
This commit is contained in:
@@ -1,313 +1,7 @@
|
||||
/* Home dashboard behaviour. All selectors are db-* scoped. */
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function updateGreeting() {
|
||||
const el = document.getElementById("db-greeting");
|
||||
if (!el) return;
|
||||
|
||||
const hour = new Date().getHours();
|
||||
if (hour < 5) el.textContent = "Late session";
|
||||
else if (hour < 12) el.textContent = "Good morning";
|
||||
else if (hour < 17) el.textContent = "Good afternoon";
|
||||
else if (hour < 21) el.textContent = "Good evening";
|
||||
else el.textContent = "Evening review";
|
||||
}
|
||||
|
||||
function updateClock() {
|
||||
const el = document.getElementById("db-clock");
|
||||
if (!el) return;
|
||||
|
||||
el.textContent = new Intl.DateTimeFormat(undefined, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
}).format(new Date());
|
||||
}
|
||||
|
||||
function getIsoWeek(date) {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const start = new Date(year, 0, 1);
|
||||
const nextYear = new Date(year + 1, 0, 1);
|
||||
const dayOfYear = Math.floor((now - start) / 86400000) + 1;
|
||||
const daysInYear = Math.round((nextYear - start) / 86400000);
|
||||
const daysLeft = Math.max(0, daysInYear - dayOfYear);
|
||||
const month = new Intl.DateTimeFormat(undefined, { month: "short" }).format(now);
|
||||
const pct = ((dayOfYear / daysInYear) * 100).toFixed(1);
|
||||
|
||||
setText("db-stat-day", dayOfYear);
|
||||
setText("db-stat-week", "W" + getIsoWeek(now));
|
||||
setText("db-stat-month", month);
|
||||
setText("db-stat-left", daysLeft);
|
||||
setText("db-year-pct", pct + "%");
|
||||
|
||||
const fill = document.getElementById("db-year-fill");
|
||||
if (fill) fill.style.width = pct + "%";
|
||||
}
|
||||
|
||||
function setText(id, value) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = value;
|
||||
}
|
||||
|
||||
function escHtml(str) {
|
||||
return String(str)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.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;
|
||||
const base = (prefix || "").replace(/\/$/, "");
|
||||
if (!base || href.startsWith(base + "/")) return href;
|
||||
return base + "/" + href;
|
||||
}
|
||||
|
||||
function isTagLink(a) {
|
||||
const href = a.getAttribute("href") || "";
|
||||
return href.includes("/tags/") || Boolean(a.querySelector(".post-tag"));
|
||||
}
|
||||
|
||||
function extractLinks(doc, max, prefix) {
|
||||
const items = [];
|
||||
const seen = new Set();
|
||||
const links = doc.querySelectorAll("#content li a[href], .org-ul li a[href], ul li a[href]");
|
||||
|
||||
for (const a of links) {
|
||||
if (isTagLink(a)) continue;
|
||||
|
||||
const href = normaliseHref(a.getAttribute("href"), prefix);
|
||||
const title = a.textContent.trim();
|
||||
if (!href || !title || seen.has(href)) continue;
|
||||
|
||||
const li = a.closest("li");
|
||||
const dateMatch = li ? li.textContent.match(/\b\d{4}-\d{2}-\d{2}\b/) : null;
|
||||
seen.add(href);
|
||||
items.push({ href, title, date: dateMatch ? dateMatch[0] : null });
|
||||
if (items.length >= max) break;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
function renderFeed(ulId, items) {
|
||||
const ul = document.getElementById(ulId);
|
||||
if (!ul || !items.length) return;
|
||||
|
||||
ul.innerHTML = items
|
||||
.map(({ href, title, date }) => (
|
||||
`<li class="db-feed__item">` +
|
||||
`<span class="db-feed__dot"></span>` +
|
||||
`<a href="${escHtml(href)}">${escHtml(title)}</a>` +
|
||||
(date ? `<span class="db-feed__meta">${escHtml(date)}</span>` : "") +
|
||||
`</li>`
|
||||
))
|
||||
.join("");
|
||||
}
|
||||
|
||||
async function loadFeed(listUrl, ulId, max, prefix) {
|
||||
try {
|
||||
const resp = await fetch(listUrl, { credentials: "same-origin" });
|
||||
if (!resp.ok) return;
|
||||
|
||||
const html = await resp.text();
|
||||
const doc = new DOMParser().parseFromString(html, "text/html");
|
||||
renderFeed(ulId, extractLinks(doc, max, prefix));
|
||||
} catch (_) {
|
||||
/* Fallback links remain in the HTML. */
|
||||
}
|
||||
}
|
||||
|
||||
function commentSlug(comment) {
|
||||
return comment.pageSlug || comment.page_slug || "";
|
||||
}
|
||||
|
||||
function commentDate(comment) {
|
||||
return comment.created_at || comment.createdAt || "";
|
||||
}
|
||||
|
||||
function commentHref(page, comment) {
|
||||
if (!page?.url) return null;
|
||||
if (!comment.id) return page.url + "#comments";
|
||||
return page.url + "#comment-" + encodeURIComponent(comment.id);
|
||||
}
|
||||
|
||||
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 = commentHref(page, comment);
|
||||
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");
|
||||
if (!input || !nav) return;
|
||||
|
||||
const items = Array.from(nav.querySelectorAll(".db-qn-item"));
|
||||
const applyFilter = () => {
|
||||
const query = input.value.trim().toLowerCase();
|
||||
items.forEach((item) => {
|
||||
const haystack = [
|
||||
item.textContent,
|
||||
item.getAttribute("href"),
|
||||
item.dataset.keywords,
|
||||
].join(" ").toLowerCase();
|
||||
item.classList.toggle("is-hidden", Boolean(query && !haystack.includes(query)));
|
||||
});
|
||||
};
|
||||
|
||||
input.addEventListener("input", applyFilter);
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "/" && !/^(input|textarea|select)$/i.test(event.target.tagName)) {
|
||||
event.preventDefault();
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
updateGreeting();
|
||||
updateClock();
|
||||
updateStats();
|
||||
initCommandFilter();
|
||||
|
||||
setInterval(updateClock, 1000);
|
||||
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") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
var script = document.createElement("script");
|
||||
script.src = "/assets/scripts/pages/home-dashboard.js";
|
||||
script.defer = true;
|
||||
document.head.appendChild(script);
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user