diff --git a/src/app.js b/src/app.js index 6e5b811..4310bf7 100644 --- a/src/app.js +++ b/src/app.js @@ -1916,6 +1916,51 @@ settingsDialog.close(); }); + // ---------- changelog dialog ---------- + // Shows the *loaded* build's full changelog: the plain URL is served + // cache-first by the controlling service worker, so the list always matches + // the version actually running (the update banner handles what's newer). + const changelogDialog = document.getElementById("changelog-dialog"); + const changelogList = document.getElementById("changelog-list"); + const changelogEmpty = document.getElementById("changelog-empty"); + + function formatChangelogDate(iso) { + const [y, m, d] = (iso || "").split("-").map(Number); + if (!y || !m || !d) return iso || ""; + return new Date(y, m - 1, d).toLocaleDateString(undefined, { + year: "numeric", month: "short", day: "numeric", + }); + } + + document.getElementById("changelog-btn").addEventListener("click", async () => { + let entries = []; + try { + const res = await fetch("changelog.json"); + if (res.ok) { + const body = await res.json(); + if (Array.isArray(body)) entries = body.filter(e => e && e.text); + } + } catch { /* fall through to empty state */ } + + changelogList.innerHTML = ""; + changelogEmpty.hidden = entries.length > 0; + let lastDate = null; + for (const e of entries) { + if (e.date !== lastDate) { + lastDate = e.date; + const dt = document.createElement("li"); + dt.className = "changelog-date"; + dt.textContent = formatChangelogDate(e.date); + changelogList.appendChild(dt); + } + const li = document.createElement("li"); + li.className = "changelog-entry"; + li.textContent = e.text; + changelogList.appendChild(li); + } + changelogDialog.showModal(); + }); + // ---------- exercise dialog (add / edit a training exercise) ---------- const exerciseDialog = document.getElementById("exercise-dialog"); const exerciseForm = document.getElementById("exercise-form"); diff --git a/src/changelog.json b/src/changelog.json index d305978..eb87916 100644 --- a/src/changelog.json +++ b/src/changelog.json @@ -1,4 +1,5 @@ [ + { "date": "2026-07-12", "text": "Browse the full changelog from the bottom of the page" }, { "date": "2026-07-12", "text": "Finer-grained y-axis on the daily counts chart" }, { "date": "2026-07-12", "text": "The update banner now lists what changed in the new version" }, { "date": "2026-07-12", "text": "Fixed adding an exercise on iPhone: stale app updates, and the keyboard's Go key discarding the input" }, diff --git a/src/index.html b/src/index.html index 94779ad..3432e0c 100644 --- a/src/index.html +++ b/src/index.html @@ -230,8 +230,23 @@

No events logged for this day.

+ + + +
+

Changelog

+ + + + + +
+
+

Puppy settings

diff --git a/src/style.css b/src/style.css index 5dfd4fc..152b199 100644 --- a/src/style.css +++ b/src/style.css @@ -695,6 +695,40 @@ input.switch:checked::after { transform: translateX(18px); } opacity: 0.92; } .update-changelog[hidden] { display: none; } + +.app-footer { + text-align: center; + padding: 4px 0 24px; +} +.app-footer .linklike { color: var(--muted); font-size: 0.8rem; } + +.changelog-list { + list-style: none; + margin: 0 0 12px; + padding: 0; + max-height: 60vh; + overflow-y: auto; +} +.changelog-date { + color: var(--muted); + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.04em; + margin: 10px 0 4px; +} +.changelog-date:first-child { margin-top: 0; } +.changelog-entry { + font-size: 0.9rem; + line-height: 1.45; + padding: 3px 0 3px 14px; + position: relative; +} +.changelog-entry::before { + content: "•"; + position: absolute; + left: 2px; + color: var(--accent); +} .update-banner-msg { font-size: 0.9rem; font-weight: 600; } .update-banner-actions { display: flex; gap: 8px; } .update-banner-btn {