feat: honor OCR text and tag scope in search Chapters/Mangas views

The Chapters/Mangas aggregation views accept an OCR ?text= filter and the
page search intersects tags, but the client dropped both: any text query
collapsed every view into a flat page search that discarded the selected tag
and grouping. Add text to AggregateOptions, thread it into
listTaggedChapters/listTaggedMangas, and rework the search loader so a
tag-scoped view runs the aggregation (optionally text-filtered) and the page
search passes the selected tag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-11 14:58:48 +02:00
parent 1ed1a134ea
commit 69a9309c54
4 changed files with 43 additions and 11 deletions

View File

@@ -103,26 +103,44 @@ export const load: PageLoad = async ({ url }) => {
// every tag / view / sort / text change instead of freezing the old list.
const results = (async () => {
try {
// Content search takes precedence over tag browsing.
// Chapters / Mangas are tag-scoped aggregation views. When a tag is
// selected, run the aggregation — optionally filtered by the OCR
// `text` — so the selected view AND tag are honoured. Previously any
// `text` collapsed every view into a flat page search, discarding
// both the tag and the chapters/mangas grouping.
if (tag && view === 'chapters') {
const r = await listTaggedChapters({
tag,
order,
limit: 100,
text: text || undefined
});
return { ...emptyResults, chapters: r.items, total: r.page.total ?? 0 };
}
if (tag && view === 'mangas') {
const r = await listTaggedMangas({
tag,
order,
limit: 100,
text: text || undefined
});
return { ...emptyResults, mangas: r.items, total: r.page.total ?? 0 };
}
// Pages view (or a content search with no tag): a positive filter
// runs the page search — intersecting the selected tag with the OCR
// text / content-warning filters instead of ignoring the tag.
if (contentSearch) {
const r = await searchPages({
text: text || undefined,
tags: tag ? [tag] : undefined,
cwInclude,
cwExclude,
limit: 100
});
return { ...emptyResults, results: r.items, total: r.page.total ?? 0 };
}
// No tag selected → just the chip cloud, no results.
// No tag selected and no content filter → just the chip cloud.
if (!tag) return emptyResults;
if (view === 'chapters') {
const r = await listTaggedChapters({ tag, order, limit: 100 });
return { ...emptyResults, chapters: r.items, total: r.page.total ?? 0 };
}
if (view === 'mangas') {
const r = await listTaggedMangas({ tag, order, limit: 100 });
return { ...emptyResults, mangas: r.items, total: r.page.total ?? 0 };
}
const r = await listMyPageTags({ tag, limit: 100 });
return { ...emptyResults, pages: r.items, total: r.page.total ?? 0 };
} catch (e) {