import { ApiError } from '$lib/api/client'; import { listMyDistinctPageTags, listMyPageTags, listTaggedChapters, listTaggedMangas, type PageTagSummary, type TaggedChapterAggregate, type TaggedMangaAggregate, type TaggedPageItem } from '$lib/api/page_tags'; import type { PageLoad } from './$types'; export const ssr = false; type View = 'pages' | 'chapters' | 'mangas'; type Order = 'desc' | 'asc'; /** * Loader for the /search page. URL is the source of truth — refresh * or share a link lands the user on the same view. * * - `?tag=` exact-match tag filter. Empty → no results, just the * chip cloud for browsing. * - `?view=pages|chapters|mangas` — defaults to `pages` when omitted. * - `?order=desc|asc` — only meaningful for chapters/mangas tabs. * `desc` (most matches first) is the default. * * `?text=` is reserved for the planned OCR text-search input. The * backend rejects it with 501 + stable code * `text_search_not_yet_supported` today; the frontend never sets it. */ export const load: PageLoad = async ({ url }) => { const tag = url.searchParams.get('tag'); const viewParam = url.searchParams.get('view'); const view: View = viewParam === 'chapters' || viewParam === 'mangas' ? viewParam : 'pages'; const order: Order = url.searchParams.get('order') === 'asc' ? 'asc' : 'desc'; const empty = { authenticated: true, tag, view, order, distinct: [] as PageTagSummary[], pages: [] as TaggedPageItem[], chapters: [] as TaggedChapterAggregate[], mangas: [] as TaggedMangaAggregate[], total: 0, error: null as string | null }; try { const distinct = await listMyDistinctPageTags(undefined, 100); // No tag selected → just the chip cloud. if (!tag) return { ...empty, distinct }; if (view === 'chapters') { const r = await listTaggedChapters({ tag, order, limit: 100 }); return { ...empty, distinct, chapters: r.items, total: r.page.total ?? 0 }; } if (view === 'mangas') { const r = await listTaggedMangas({ tag, order, limit: 100 }); return { ...empty, distinct, mangas: r.items, total: r.page.total ?? 0 }; } const r = await listMyPageTags({ tag, limit: 100 }); return { ...empty, distinct, pages: r.items, total: r.page.total ?? 0 }; } catch (e) { if (e instanceof ApiError && e.status === 401) { return { ...empty, authenticated: false }; } if (e instanceof ApiError) { return { ...empty, error: e.message }; } throw e; } };