Fix mobile header, merge author name variants, clearer playback errors
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f977f3294c
commit
1df566d85d
1 file changed
+18
-3
+18
-3
@@ -100,7 +100,9 @@ a.pill{text-decoration:none;color:var(--fg);display:inline-block}
|
||||
.chlist .on{color:var(--acc);font-weight:700}
|
||||
#toast{position:fixed;left:50%;bottom:110px;transform:translateX(-50%);background:var(--fg);color:var(--bg);padding:10px 16px;border-radius:99px;font-weight:600;z-index:30;opacity:0;pointer-events:none;transition:opacity .2s}
|
||||
#toast.on{opacity:1}
|
||||
@media(max-width:560px){.logo span{display:none}.hd{padding:calc(12px + env(safe-area-inset-top)) 14px 12px}main{padding:4px 14px}.grid{grid-template-columns:repeat(auto-fill,minmax(130px,1fr))}}
|
||||
.brk{display:none}
|
||||
@media(max-width:560px){.logo span{display:inline}.logo{margin-right:auto}.hd{flex-wrap:wrap;gap:10px;padding:calc(12px + env(safe-area-inset-top)) 14px 12px}
|
||||
#adminlink,#who{order:1}.brk{display:block;order:2;flex:0 0 100%;height:0}.search{order:3;margin-left:0;min-width:0}#sort{order:3;max-width:48%}main{padding:4px 14px}.grid{grid-template-columns:repeat(auto-fill,minmax(130px,1fr))}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -116,6 +118,7 @@ a.pill{text-decoration:none;color:var(--fg);display:inline-block}
|
||||
|
||||
<header><div class="hd">
|
||||
<div class="logo"><i><svg><use href="#i-book"/></svg></i><span>Audiobooks</span></div>
|
||||
<div class="brk"></div>
|
||||
<div class="search"><svg><use href="#i-search"/></svg><input id="q" type="search" placeholder="Search title, author, series"></div>
|
||||
<a class="pill hide" id="adminlink" href="/admin" style="padding:8px 12px">Admin</a>
|
||||
<button class="pill" id="who" title="Sign out" style="padding:8px 12px"></button>
|
||||
@@ -222,7 +225,15 @@ function render() {
|
||||
$('count').textContent = books.length ? `${list.length} book${list.length === 1 ? '' : 's'}` : '';
|
||||
if (sort === 'author') {
|
||||
const groups = new Map();
|
||||
for (const b of list) { const a = author(b) || 'Unknown author'; if (!groups.has(a)) groups.set(a, []); groups.get(a).push(b); }
|
||||
const labels = new Map();
|
||||
for (const b of list) {
|
||||
const a = author(b) || 'Unknown author', k = a.toLowerCase().replace(/[^\p{L}\p{N}]/gu, '');
|
||||
if (!groups.has(k)) { groups.set(k, []); labels.set(k, a); }
|
||||
groups.get(k).push(b);
|
||||
}
|
||||
for (const [k, bs] of groups) groups.set(k, { label: labels.get(k), bs });
|
||||
const sorted = [...groups.values()].sort((x, y) => x.label.localeCompare(y.label));
|
||||
groups.clear(); sorted.forEach(g => groups.set(g.label, g.bs));
|
||||
$('grid').className = '';
|
||||
$('grid').replaceChildren(...[...groups].map(([a, bs]) => {
|
||||
const s = document.createElement('section');
|
||||
@@ -312,7 +323,11 @@ $('fwd').onclick = () => skip(30); $('pch').onclick = () => jump(-1); $('nch').o
|
||||
audio.onplay = () => { ico('play', 'pause'); ico('mplay', 'pause'); };
|
||||
audio.onpause = () => { ico('play', 'play'); ico('mplay', 'play'); saveProgress(); };
|
||||
audio.onended = () => { if (current) setProg(bookId(current), { pos: 0, dur: audio.duration, t: Date.now() }); render(); };
|
||||
audio.onerror = () => toast("Playback failed (this browser can't play that format)");
|
||||
audio.onerror = () => {
|
||||
const c = audio.error && audio.error.code, why = { 1: 'aborted', 2: 'network error', 3: 'could not decode', 4: 'format or stream not supported' }[c] || 'unknown';
|
||||
console.error('audio error', c, audio.error && audio.error.message, audio.src);
|
||||
toast(`Playback failed: ${why}${current ? ' · ' + (audio.src.split('.').pop().slice(0, 5)) : ''}`);
|
||||
};
|
||||
$('seek').oninput = e => { audio.currentTime = e.target.value; };
|
||||
|
||||
// ---- cross-device sync (progress is kept by server.py; newest timestamp wins) ----
|
||||
|
||||
Reference in new issue
Block a user