Wire the new features into the app: routes, settings, Home card, styles, CI, roadmap; bump the app cache
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bcaedbab5c
commit
c51134e0e5
9 files changed
+48
-16
No files matched your search
@@ -28,3 +28,17 @@ async function homeResume(el) {
|
||||
el.querySelectorAll('a[data-book]').forEach(a => a.onclick = e => { e.preventDefault(); const b = (today.books || []).find(x => abId(x) === a.dataset.book); if (b) abSheet(b); });
|
||||
}
|
||||
const today = { books: [] };
|
||||
|
||||
// Home: how much you listened this week (podcasts and audiobooks), the day streak, and a yearly goal for audiobooks finished. The goal is kept in your synced settings.
|
||||
const lsTime = sec => { const m = Math.round(sec / 60); return m < 60 ? m + ' min' : Math.floor(m / 60) + ' h' + (m % 60 ? ' ' + (m % 60) + ' min' : ''); };
|
||||
async function homeListening(after) {
|
||||
if (!after || !(allowed('podcast') || allowed('audio'))) return;
|
||||
let s; try { s = await jfetch('/api/listening/stats'); } catch { return; }
|
||||
const goal = +store.get('read_goal', 0) || 0; if (!after.isConnected || (!s.week && !goal && !s.finishedYear)) return;
|
||||
const max = Math.max(60, ...s.last14.map(d => d.s)), card = document.createElement('div'); card.id = 'listening';
|
||||
card.innerHTML = `<h2>Listening</h2><div class="card" style="max-width:none"><div class="lsrow"><span><b>${lsTime(s.week)}</b><small>this week</small></span><span><b>${s.streak}</b><small>day${s.streak === 1 ? '' : 's'} in a row</small></span><span><b>${s.finishedYear}${goal ? ' / ' + goal : ''}</b><small>audiobooks finished this year</small></span></div>
|
||||
<div class="lsbars" role="img" aria-label="Minutes listened each of the last 14 days">${s.last14.map(d => `<i style="height:${Math.max(3, Math.round(d.s / max * 100))}%" title="${esc(d.day)}: ${lsTime(d.s)}"></i>`).join('')}</div>
|
||||
${goal ? `<div class="lsgoal"><i style="width:${Math.min(100, Math.round(s.finishedYear / goal * 100))}%"></i></div>` : ''}<div class="bar" style="margin:8px 0 0"><button class="btn ghost" id="lsgoal">${goal ? 'Change yearly goal' : 'Set a yearly goal'}</button></div></div>`;
|
||||
after.insertAdjacentElement('afterend', card);
|
||||
card.querySelector('#lsgoal').onclick = () => { const el = openSheet('Audiobooks to finish this year', '', `<form id="lsf"><label for="lsn">Goal</label><input type="number" id="lsn" min="0" max="500" value="${goal || ''}" placeholder="12" inputmode="numeric"><div class="bar"><button class="btn" style="flex:1;justify-content:center">Save</button></div></form>`); el.querySelector('#lsf').onsubmit = e => { e.preventDefault(); const n = Math.max(0, Math.min(500, Math.round(+el.querySelector('#lsn').value) || 0)); if (n) store.set('read_goal', n); else store.del('read_goal'); closeSheet(); card.remove(); homeListening(after); }; };
|
||||
}
|
||||
Reference in new issue
Block a user