diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e1ed0f..cf4ed70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,16 +9,6 @@ former name, "Daybook".) _Nothing yet._ -## [0.4.1] — 2026-09-05 - -### Changed -- Live feed updates now also keep the **source sidebar** current: as new posts - arrive, per-source and total unread counts bump, and a source posting for the - first time is added to the list (alphabetically) — all derived client-side - from the polled rows, no extra request. Sources added live stay - keyboard-navigable. Caveat: while filtered to a single source, *other* new - sources still only appear on reload (the poll is scoped to the selected view). - ## [0.4.0] — 2026-09-04 ### Added @@ -165,8 +155,7 @@ First tagged release. - Dockerised (Gunicorn + whitenoise), SQLite, `git`-based deploy with a runbook (`deploy/cloud_agent_deploy.md`) and health check. -[Unreleased]: https://git.cygnus.systems/peter/daybook/compare/v0.4.1...HEAD -[0.4.1]: https://git.cygnus.systems/peter/daybook/compare/v0.4.0...v0.4.1 +[Unreleased]: https://git.cygnus.systems/peter/daybook/compare/v0.4.0...HEAD [0.4.0]: https://git.cygnus.systems/peter/daybook/compare/v0.3.2...v0.4.0 [0.3.2]: https://git.cygnus.systems/peter/daybook/compare/v0.3.1...v0.3.2 [0.3.1]: https://git.cygnus.systems/peter/daybook/compare/v0.3.0...v0.3.1 diff --git a/daybook_project/__init__.py b/daybook_project/__init__.py index 53f5709..bc935aa 100644 --- a/daybook_project/__init__.py +++ b/daybook_project/__init__.py @@ -1,4 +1,4 @@ # Single source of truth for the app version. Bump this, commit, then tag the # commit `vX.Y.Z` and deploy. Surfaced on Settings -> About and in # GET /api/capabilities ("version"). -__version__ = "0.4.1" +__version__ = "0.4.0" diff --git a/templates/artifacts/feed.html b/templates/artifacts/feed.html index 78764fe..a240ebc 100644 --- a/templates/artifacts/feed.html +++ b/templates/artifacts/feed.html @@ -195,8 +195,7 @@ const artifactList = document.querySelector("[data-artifact-list]"); // Rows grow as older pages load, so always read them live rather than caching an array. const allRows = () => Array.from(document.querySelectorAll(".artifact-row")); - // Live-queried so sources added by live updates are keyboard-navigable too. - const sourceLinks = () => Array.from(document.querySelectorAll(".source-link")); + const sourceLinks = Array.from(document.querySelectorAll(".source-link")); const csrfToken = document.querySelector("[name=csrfmiddlewaretoken]")?.value || ""; const escapeHtml = (value) => value.replace(/[&<>"]/g, (character) => ({ @@ -384,66 +383,6 @@ }); }; - const findSourceLink = (name) => - sourceLinks().find((link) => link.querySelector(".source-name")?.textContent.trim() === name); - - const bumpSourceBadge = (link, delta) => { - let badge = link.querySelector(".source-count"); - if (!badge) { - badge = document.createElement("span"); - badge.className = "source-count"; - badge.textContent = "0"; - link.appendChild(badge); - } - badge.textContent = String((Number(badge.textContent) || 0) + delta); - }; - - const addSourceLink = (name, count) => { - const params = new URLSearchParams(); - params.set("source", name); - if (feed.dataset.selectedLabel) params.set("label", feed.dataset.selectedLabel); - if (feed.dataset.selectedKind) params.set("kind", feed.dataset.selectedKind); - if (feed.dataset.titleQuery) params.set("q", feed.dataset.titleQuery); - params.set("view", feed.dataset.selectedView || "rendered"); - params.set("preview", "none"); - - const link = document.createElement("a"); - link.className = "source-link"; - link.href = `?${params.toString()}`; - link.innerHTML = - `${escapeHtml(name)}` + - `${count}`; - - // Insert alphabetically among the per-source links (after "All sources"). - const list = document.querySelector(".source-list"); - const others = sourceLinks().filter( - (l) => l.querySelector(".source-name")?.textContent.trim() !== "All sources", - ); - const after = others.find( - (l) => (l.querySelector(".source-name")?.textContent.trim() || "") > name, - ); - list.insertBefore(link, after || null); - }; - - // From the newly-arrived rows: bump each source's unread count (adding a - // sidebar entry for a source seen for the first time) plus the total. - const registerNewSources = (rows) => { - const counts = {}; - rows.forEach((row) => { - const source = row.dataset.source; - if (source) counts[source] = (counts[source] || 0) + 1; - }); - let total = 0; - Object.entries(counts).forEach(([source, n]) => { - total += n; - const existing = findSourceLink(source); - if (existing) bumpSourceBadge(existing, n); - else addSourceLink(source, n); - }); - const allLink = findSourceLink("All sources"); - if (allLink && total) bumpSourceBadge(allLink, total); - }; - const renderPreview = (row, pushState = true) => { navigationMode = "artifacts"; markRead(row); @@ -499,13 +438,12 @@ }; const moveSource = (direction) => { - const links = sourceLinks(); - if (!links.length) return; + if (!sourceLinks.length) return; navigationMode = "sources"; const current = document.querySelector(".source-link.selected"); - const currentIndex = current ? links.indexOf(current) : 0; - const nextIndex = Math.max(0, Math.min(links.length - 1, currentIndex + direction)); - const nextSource = links[nextIndex]; + const currentIndex = current ? sourceLinks.indexOf(current) : 0; + const nextIndex = Math.max(0, Math.min(sourceLinks.length - 1, currentIndex + direction)); + const nextSource = sourceLinks[nextIndex]; if (nextSource && nextSource !== current) window.location.href = nextSource.href; }; @@ -685,7 +623,6 @@ node = node.nextElementSibling; } markArrived(inserted); - registerNewSources(inserted); // update sidebar: counts + any new source liveSince = data.newest; const dayCount = group.querySelector(".day-separator-count"); if (dayCount) dayCount.textContent = String((parseInt(dayCount.textContent, 10) || 0) + data.count);