fix(mangas): address review on sort feature — alias, index, validation, a11y

Backend
- sort=recent stays a back-compat alias for created (parse_sort); invalid
  sort/order now return the structured 422 envelope instead of plain-text 400
- per-field default direction on omitted order (dates desc, text asc), matching
  the frontend so a bare ?sort=<field> reads the same in UI and API
- migration 0033: index mangas(updated_at DESC, id) backing the default sort
  and its id tie-break; NULLS LAST now applied only to the nullable author key
- tests: recent alias, per-field default (title+author), invalid-value 422,
  and a tie-break test that pins ordering by ascending id (mutation-verified)

Frontend
- pure sort helpers extracted to $lib/mangaSort with unit tests; coerceSort
  honors the recent alias so pasted/legacy URLs resolve to the same field
- SegmentedControl: roving tabindex + arrow/Home/End keyboard nav, anchored on
  focus so rapid keypresses don't stick
- UX: visible "Direction" labels (desktop + mobile), mobile sort-sheet section
  headings and a "Done" button; README sort/order contract updated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-25 07:15:33 +02:00
parent 1079a0151a
commit 78edea4277
11 changed files with 650 additions and 73 deletions

View File

@@ -81,7 +81,7 @@ Everything is namespaced under `/api/v1/`. `/api/*` outside the version prefix i
| Method | Path | Description |
| ------ | ------------------------------------------------------- | ------------------------------------------ |
| GET | `/api/v1/health` | Liveness probe. |
| GET | `/api/v1/mangas?search=&sort=recent|title&limit=&offset=` | List/search mangas. Trigram fuzzy search. |
| GET | `/api/v1/mangas?search=&sort=created\|updated\|title\|author&order=asc\|desc&limit=&offset=` | List/search mangas. Trigram fuzzy search. `sort` defaults to `updated`; `order` defaults per field (dates `desc`, text `asc`). `sort=recent` is a back-compat alias for `created`. |
| GET | `/api/v1/mangas/{id}` | Single manga. |
| GET | `/api/v1/mangas/{id}/chapters` | Paginated chapter list, ordered by number. |
| GET | `/api/v1/mangas/{id}/chapters/{n}` | Single chapter. |