diff --git a/app/public/app.js b/app/public/app.js index dcfcea0..1f65c4f 100644 --- a/app/public/app.js +++ b/app/public/app.js @@ -119,7 +119,9 @@ const chapLabel = c => (c.num ? `Cap. ${c.num}` : 'Oneshot') + (c.title ? ` — const readUrl = (mangaId, chapterId, page) => `#/read/${mangaId}/${chapterId}${page != null ? `?page=${page + 1}` : ''}` // ---------- Router ---------- +let prevHash = '', curHash = '' // para volver atrás sin pasar por el lector async function router() { + if (location.hash !== curHash) { prevHash = curHash; curHash = location.hash } if (cleanup) { cleanup(); cleanup = null } document.body.classList.remove('reading') const [pathPart, query] = location.hash.slice(1).split('?') @@ -626,7 +628,9 @@ async function viewManga(id, langOverride) { if (!confirm(`¿Dejar de leer «${manga.title}»?\nSe quitará del historial, se borrará el progreso de sus capítulos y dejarás de seguirlo.`)) return await api(`/api/history/${id}`, { method: 'DELETE' }) toast('Quitado del historial') - viewManga(id, langOverride) + // Volver a donde se estaba (salvo el lector o la propia ficha, que lo volverían a marcar) o al inicio. + const back = prevHash && !prevHash.startsWith('#/read/') && !prevHash.startsWith(`#/manga/${id}`) && prevHash !== '#/login' + location.hash = back ? prevHash : '#/' }) // Cerrar el menú ⋯ al pulsar fuera. const menu = $('.menu', app) @@ -1331,15 +1335,20 @@ async function viewHistory() { const hist = await api('/api/history') app.innerHTML = `

Historial de lectura

${hist.length ? '' : '

Aún no has leído nada.

'} -
${hist.map(h => ` -
- ${continueCard(h).replace('class="cont"', 'style="display:flex;gap:12px;flex:1;min-width:0;align-items:center"')} -
- ${icon('book')} Ficha - -
-
`).join('')}
` - app.querySelectorAll('[data-del]').forEach(b => b.addEventListener('click', async () => { +
${hist.map(h => { + const pct = h.total_pages ? Math.round(((h.page + 1) / h.total_pages) * 100) : 0 + return ` + + ${h.finished ? 'Terminado' : h.hasNew ? 'Caps. nuevos' : ''} + +
+
${esc(h.manga_title)}
+
${h.chapter_num ? `Cap. ${esc(h.chapter_num)}` : 'Oneshot'} · ${timeAgo(h.updated_at)}
+
` + }).join('')}
` + app.querySelectorAll('[data-del]').forEach(b => b.addEventListener('click', async e => { + e.preventDefault() + e.stopPropagation() if (!confirm('¿Borrar el historial de este manga?')) return await api(`/api/history/${b.dataset.del}`, { method: 'DELETE' }) viewHistory() diff --git a/app/public/style.css b/app/public/style.css index f7c9a28..d82256f 100644 --- a/app/public/style.css +++ b/app/public/style.css @@ -303,3 +303,14 @@ body.noscroll { overflow: hidden; } .lb-img { padding: 10px; } .lb-side { max-height: 48vh; padding: 12px 14px max(12px, env(safe-area-inset-bottom)); } } + +/* Historial: tarjetas verticales */ +.hcard .bar { margin: 0; height: 5px; } +.hcard .t { padding-bottom: 2px; } +.hcard .sub { margin-top: 0; } +.hcard .corner { position: absolute; top: 8px; left: 8px; } +.hdel { position: absolute; top: 6px; right: 6px; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 8px; border: 0; + background: rgba(20, 18, 26, .75); color: var(--muted); cursor: pointer; opacity: 0; transition: opacity .15s; } +.hcard:hover .hdel, .hdel:focus-visible { opacity: 1; } +.hdel:hover { color: var(--danger); } +@media (hover: none) { .hdel { opacity: 1; } }