Release notes + roadmap: /whats-new page, Overview What's new card, Admin > Releases editor

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-14 04:54:43 -05:00
parent f7b911bab6
commit b3523e9dc4
10 changed files with 171 additions and 9 deletions
+17
View File
@@ -441,8 +441,25 @@
el.innerHTML = '<div class="lt-top"><span class="lt-you">YOU</span></div><div class="lt-stem"></div>' + rowFor(1) + rowFor(2) + rowFor(3);
} catch (e) {}
}
// "What's new" card: latest notes + what is being built; a dot marks notes newer than the member's last look (Marty, 2026-09-14)
let newsLoaded = false;
async function loadNews() {
if (newsLoaded || !$('newsCard')) return; newsLoaded = true;
try {
const r = await (await fetch('/api/releases')).json();
if (!r.notes.length && !r.roadmap.length) return;
let seen = ''; try { seen = localStorage.getItem('iap.news.seen') || ''; } catch (e) {}
const esc = t => String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
const notes = r.notes.slice(0, 3).map(n => '<p style="margin:0 0 8px">' + (n.date > seen ? '<span style="color:var(--mint)">●</span> ' : '') + '<b>' + esc(n.title) + '</b> <span class="muted">' + esc(n.date) + '</span></p>').join('');
const rm = r.roadmap.filter(x => x.status === 'building').slice(0, 2).map(x => '<p class="muted" style="margin:0 0 6px">Building: ' + esc(x.title) + (x.eta ? ' (' + esc(x.eta) + ')' : '') + '</p>').join('');
$('newsList').innerHTML = notes + rm + '<p style="margin:6px 0 0"><a href="/whats-new" target="_blank" rel="noopener" style="color:var(--mint)">All release notes and the roadmap →</a></p>';
$('newsCard').hidden = false;
$('newsCard').addEventListener('click', () => { try { localStorage.setItem('iap.news.seen', r.latest || ''); } catch (e) {} $('newsList').querySelectorAll('span[style*="mint"]').forEach(s => { if (s.textContent === '●') s.remove(); }); }, { once: true });
} catch (e) {}
}
async function loadDashboard() {
try {
loadNews();
const d = await (await fetch('/api/my/dashboard')).json();
if (d.error) return;
chatSync(d);