The detail loader now streams its six-call bundle instead of blocking
navigation on it. The page component is a thin {#await} wrapper: it shows a
MangaDetailSkeleton (cover + meta + chapter rows) while the bundle loads,
renders the extracted DetailView once resolved, and shows an inline
not-found on a 404 (previously the framework error page). Extracting
DetailView also makes it remount per navigation, so its tag/bookmark/reaction
state re-seeds cleanly on manga-to-manga moves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
1.1 KiB
Svelte
43 lines
1.1 KiB
Svelte
<script lang="ts">
|
|
import { ApiError } from '$lib/api/client';
|
|
import MangaDetailSkeleton from '$lib/components/MangaDetailSkeleton.svelte';
|
|
import DetailView from './DetailView.svelte';
|
|
|
|
let { data } = $props();
|
|
</script>
|
|
|
|
{#await data.bundle}
|
|
<MangaDetailSkeleton />
|
|
{:then bundle}
|
|
<DetailView data={bundle} />
|
|
{:catch err}
|
|
<div class="detail-error" role="alert" data-testid="detail-error">
|
|
{#if err instanceof ApiError && err.status === 404}
|
|
<h1>Manga not found</h1>
|
|
<p>This manga may have been removed.</p>
|
|
{:else}
|
|
<h1>Couldn't load this manga</h1>
|
|
<p>{err instanceof Error ? err.message : 'Please try again.'}</p>
|
|
{/if}
|
|
<a href="/">Back to browse</a>
|
|
</div>
|
|
{/await}
|
|
|
|
<style>
|
|
.detail-error {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.detail-error h1 {
|
|
margin: 0;
|
|
}
|
|
|
|
.detail-error p {
|
|
color: var(--text-muted);
|
|
margin: 0;
|
|
}
|
|
</style>
|