diff --git a/assets/scripts/zhd.js b/assets/scripts/zhd.js index 3b38234..2d6ed9a 100644 --- a/assets/scripts/zhd.js +++ b/assets/scripts/zhd.js @@ -1,186 +1,166 @@ -/* ============================================================= - dashboard.js — Home page dashboard behaviour - Runs after DOM is ready. All IDs are db-* scoped. - ============================================================= */ +/* Home dashboard behaviour. All selectors are db-* scoped. */ (function () { "use strict"; - /* ── Greeting ──────────────────────────────────────────────── */ - function updateGreeting() { const el = document.getElementById("db-greeting"); if (!el) return; - const h = new Date().getHours(); - if (h < 5) el.textContent = "Burning the midnight oil"; - else if (h < 12) el.textContent = "Good morning"; - else if (h < 17) el.textContent = "Good afternoon"; - else if (h < 21) el.textContent = "Good evening"; - else el.textContent = "Good night"; - } - /* ── Live clock ────────────────────────────────────────────── */ + 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; - const now = new Date(); - const pad = (n) => String(n).padStart(2, "0"); - el.textContent = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`; + + el.textContent = new Intl.DateTimeFormat(undefined, { + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + hour12: false, + }).format(new Date()); } - /* ── Date stats ────────────────────────────────────────────── */ + 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(); - - // Day of year - const start = new Date(year, 0, 0); - const diff = now - start; - const oneDay = 1000 * 60 * 60 * 24; - const dayOfYear = Math.floor(diff / oneDay); - - // ISO week number - const d = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())); - const dayNum = d.getUTCDay() || 7; - d.setUTCDate(d.getUTCDate() + 4 - dayNum); - const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); - const weekNum = Math.ceil((((d - yearStart) / 86400000) + 1) / 7); - - // Days left - const isLeap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - const daysInYear = isLeap ? 366 : 365; - const daysLeft = daysInYear - dayOfYear; - - // Month name - const months = [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - ]; - - // Write out - const set = (id, val) => { - const el = document.getElementById(id); - if (el) el.textContent = val; - }; - - set("db-stat-day", dayOfYear); - set("db-stat-week", "W" + weekNum); - set("db-stat-month", months[now.getMonth()]); - set("db-stat-left", daysLeft); - - // Year progress bar + 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"); - const label = document.getElementById("db-year-pct"); - if (fill) fill.style.width = pct + "%"; - if (label) label.textContent = pct + "%"; + if (fill) fill.style.width = pct + "%"; } - /* ── Feed builder ──────────────────────────────────────────── */ - - /** - * Parse a simple HTML sitemap/list page and extract links. - * Looks for
  • elements containing tags. - * @param {Document} doc - parsed document - * @param {number} max - max items to return - * @param {string} prefix - path prefix to prepend to relative hrefs (e.g. "/blogs") - * @returns {{ href: string, title: string, date: string|null }[]} - */ - function extractLinks(doc, max, prefix) { - const base = (prefix || "").replace(/\/$/, ""); // strip trailing slash - const items = []; - // org-publish sitemaps use
  • inside #content - const lis = doc.querySelectorAll("#content li, .org-ul li, ul li"); - for (const li of lis) { - const a = li.querySelector("a[href]"); - if (!a) continue; - let href = a.getAttribute("href"); - if (!href || href.startsWith("http")) continue; // skip external - // Prepend the section prefix when the href doesn't already start with it - if (base && !href.startsWith(base)) { - // href may start with "/" or be relative like "2026/03-march/foo.html" - href = href.startsWith("/") - ? base + href - : base + "/" + href; - } - const title = a.textContent.trim(); - if (!title) continue; - // Grab any date text that follows the link - const dateMatch = li.textContent.replace(title, "").match(/\d{4}-\d{2}-\d{2}/); - items.push({ href, title, date: dateMatch ? dateMatch[0] : null }); - if (items.length >= max) break; - } - return items; - } - - /** - * Render items into a db-feed