feat: paginate list views, fix stale page titles, tidy admin filter bar

Bundle of small UI/UX fixes plus a build hygiene tweak.

* List pagination — Home (`/`) and `/authors/[id]` silently capped at
  the backend default of 50 with no UI to advance. New reusable
  `Pager.svelte` (Prev/Next + numbered with ellipsis), URL-synced
  `?page=N`, and filter/search/sort reset to page 1 so users aren't
  stranded on an out-of-range page. Count label now shows a range
  ("Showing 51–100 of 237").

* Stale page title — Pages without a `<svelte:head><title>` left the
  document title at whatever the last manga / author / collection page
  set it to. Move static-route titles into a route-id → title map in
  the root layout and invert every dynamic title to brand-first
  (`Mangalord | {X}`) for consistency.

* Admin filter bar — `/admin/mangas` search input had `flex: 1` and
  ballooned across the row, shoving the sync-state select + Search
  button to the far right. Cap at 24rem, vertical-align the row, and
  promote the previously aria-only "Sync state" label to visible text.

* Build hygiene — `backend/target` had grown to 68 GiB. Cleaned and
  added `[profile.dev] debug = "line-tables-only"` (and `[profile.test]`
  too) to cut future dev builds by ~50–70% while keeping line numbers
  in backtraces.

Also: configure vitest to resolve Svelte's browser entry so
`@testing-library/svelte` can mount components in jsdom — needed for
the new `Pager.svelte.test.ts`.

Bump 0.48.0 -> 0.49.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-01 21:18:53 +02:00
parent e50fc093c3
commit 5c22dfdb41
22 changed files with 501 additions and 53 deletions

View File

@@ -71,16 +71,19 @@
>
<input
type="search"
placeholder="search by title"
placeholder="Search by title"
bind:value={search}
data-testid="admin-mangas-search"
/>
<select bind:value={syncFilter} aria-label="sync state">
<option value="">all states</option>
<option value="in_progress">in progress</option>
<option value="dropped">dropped</option>
<option value="synced">synced</option>
</select>
<label class="sync-label">
<span>Sync state</span>
<select bind:value={syncFilter} aria-label="sync state">
<option value="">All</option>
<option value="in_progress">In progress</option>
<option value="dropped">Dropped</option>
<option value="synced">Synced</option>
</select>
</label>
<button type="submit">Search</button>
</form>
@@ -173,17 +176,28 @@
}
form {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-3);
}
input[type='search'] {
flex: 1;
min-width: 0;
max-width: 24rem;
padding: var(--space-2) var(--space-3);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--surface);
color: var(--text);
}
.sync-label {
display: inline-flex;
align-items: center;
gap: var(--space-2);
color: var(--text-muted);
font-size: var(--font-sm);
}
select {
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-md);