Library: "Continue where you left off" row with a per-user setting
One fixed row above the library showing the five most recently read, unfinished manga with the normal tiles (they stay in the grid as well). It ignores search and filters, hides while sorted by "Recently read", and can be turned off under Settings > Reading > Library page (continueRow, default on). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e9da27e688
commit
1ddefaa7ac
7 files changed
+46
-13
No files matched your search
+22
-11
@@ -55,6 +55,14 @@
|
||||
h('option', { value: 'grouped' }, 'Group collections'), h('option', { value: 'expanded' }, 'Expand collections'), h('option', { value: 'individual' }, 'Individual manga'));
|
||||
grouping.value = ['grouped', 'expanded', 'individual'].includes(store.get('grouping')) ? store.get('grouping') : 'grouped';
|
||||
grouping.onchange = render;
|
||||
// Started but unfinished manga, most recently read first. Ignores the filters below on purpose,
|
||||
// and the same manga still appears in the grid.
|
||||
const continueItems = data.mangas.filter(m => m.lastRead && m.read < m.chapters)
|
||||
.sort((a, b) => b.lastRead - a.lastRead).slice(0, 5);
|
||||
const continueRow = h('section', { class: 'continue-row', 'aria-label': 'Continue where you left off', hidden: true },
|
||||
h('div', { class: 'continue-banner' }, h('span', { 'aria-hidden': 'true' }, '▶'), 'Continue where you left off'),
|
||||
h('div', { class: 'continue-tiles' }, continueItems.map(m => tile(m))));
|
||||
main.append(continueRow);
|
||||
if (storyAvailable) {
|
||||
const most = data.mangas.find(manga => manga.id === data.reading.mostTimeMangaId);
|
||||
const latest = data.mangas.find(manga => manga.id === data.reading.lastMangaId);
|
||||
@@ -95,8 +103,22 @@
|
||||
return direction * (at - bt) || a.title.localeCompare(b.title);
|
||||
}
|
||||
|
||||
function tile(m) {
|
||||
const cover = m.isCollection && m.coverMode === 'mosaic' && m.covers.length
|
||||
? h('div', { class: 'cv collection-mosaic' }, m.covers.map(src => h('img', { loading: 'lazy', src, alt: '' })))
|
||||
: h('div', { class: 'cv' }, m.cover ? h('img', { loading: 'lazy', src: m.cover, alt: '' }) : null);
|
||||
return h('a', { class: 'tile', href: m.isCollection ? 'collection.html?' + qsa({ id: m.id }) : mangaUrl(m.id) },
|
||||
cover, m.isCollection ? h('span', { class: 'collection-count' }, `${m.members.length} manga`) : null,
|
||||
m.unread ? h('span', { class: 'badge' }, m.unread + ' new') : null,
|
||||
h('div', { class: 't' }, m.title),
|
||||
h('div', { class: 's' }, [m.firstRelease, m.status, m.read ? `${m.read} / ${m.chapters} read` : `${m.chapters} chapters`].filter(Boolean).join(' · ')),
|
||||
m.read ? h('div', { class: 'prog' }, h('i', { style: `width:${Math.round((100 * m.read) / Math.max(1, m.chapters))}%` })) : null);
|
||||
}
|
||||
|
||||
function render() {
|
||||
store.set('filter', filter.value); store.set('sort', sort.value); store.set('status', status.value); store.set('grouping', grouping.value);
|
||||
// "Recently read" already puts these first, so the row would only repeat them.
|
||||
continueRow.hidden = !me.settings.continueRow || sort.value === 'read' || !continueItems.length;
|
||||
const q = filter.value.trim().toLowerCase();
|
||||
const groups = (data.collections || []).filter(c => c.grouped);
|
||||
const membership = new Set(groups.flatMap(c => c.members.map(m => m.id)));
|
||||
@@ -125,17 +147,6 @@
|
||||
}
|
||||
resultCount.textContent = `${list.length} results · ${data.mangas.length} manga in the library`;
|
||||
grid.textContent = '';
|
||||
const tile = m => {
|
||||
const cover = m.isCollection && m.coverMode === 'mosaic' && m.covers.length
|
||||
? h('div', { class: 'cv collection-mosaic' }, m.covers.map(src => h('img', { loading: 'lazy', src, alt: '' })))
|
||||
: h('div', { class: 'cv' }, m.cover ? h('img', { loading: 'lazy', src: m.cover, alt: '' }) : null);
|
||||
return h('a', { class: 'tile', href: m.isCollection ? 'collection.html?' + qsa({ id: m.id }) : mangaUrl(m.id) },
|
||||
cover, m.isCollection ? h('span', { class: 'collection-count' }, `${m.members.length} manga`) : null,
|
||||
m.unread ? h('span', { class: 'badge' }, m.unread + ' new') : null,
|
||||
h('div', { class: 't' }, m.title),
|
||||
h('div', { class: 's' }, [m.firstRelease, m.status, m.read ? `${m.read} / ${m.chapters} read` : `${m.chapters} chapters`].filter(Boolean).join(' · ')),
|
||||
m.read ? h('div', { class: 'prog' }, h('i', { style: `width:${Math.round((100 * m.read) / Math.max(1, m.chapters))}%` })) : null);
|
||||
};
|
||||
if (grouping.value === 'expanded') {
|
||||
const visible = new Set(list.map(m => m.id));
|
||||
for (const c of groups) {
|
||||
|
||||
Reference in new issue
Block a user