Browse search + series numbering rework + kebab fix #98

Merged
bvandeusen merged 4 commits from dev into main 2026-06-12 00:14:31 -04:00
Owner

Merges the work landed on dev since the last main release.

Browse: sticky tabs + per-tab search bar (server-side, scope-aware)

  • Tab strip (Posts/Artists/Tags) + a shared search field rolled into one sticky block pinned under the 64px TopNav, so neither scrolls away.
  • Posts gains server-side text search (it had none): PostFeedService.scroll()/around() + /api/posts accept q (ILIKE over post_title OR description), applied inside the artist/platform WHERE so search stays scoped to the active filter. Scope shown as clearable chips; term is deep-linkable (/browse?tab=posts&q=…).
  • Artists/Tags search consolidated into the sticky bar; their inner search boxes removed, platform/kind filters retained.
  • Posts empty state distinguishes "no matches" from "no posts yet".

Series: operator-set sparse page numbering

  • Replaces the auto-renumber model (which had overwritten hand-set numbers) with operator-set numbers: gaps allowed, fill without moving neighbors, type-on-card editing, one placeholder block per gap, pending-tray "place from page N".

Fix

  • Round the kebab backing on series cards (was a translucent square behind the round ⋮).

CI green on dev (run 959). No new migrations in the Browse work; series numbering shipped its migration in an earlier dev push.

🤖 Generated with Claude Code

Merges the work landed on dev since the last main release. ## Browse: sticky tabs + per-tab search bar (server-side, scope-aware) - Tab strip (Posts/Artists/Tags) + a shared search field rolled into one sticky block pinned under the 64px TopNav, so neither scrolls away. - **Posts** gains server-side text search (it had none): `PostFeedService.scroll()/around()` + `/api/posts` accept `q` (ILIKE over `post_title` OR `description`), applied inside the artist/platform WHERE so search stays scoped to the active filter. Scope shown as clearable chips; term is deep-linkable (`/browse?tab=posts&q=…`). - **Artists/Tags** search consolidated into the sticky bar; their inner search boxes removed, platform/kind filters retained. - Posts empty state distinguishes "no matches" from "no posts yet". ## Series: operator-set sparse page numbering - Replaces the auto-renumber model (which had overwritten hand-set numbers) with operator-set numbers: gaps allowed, fill without moving neighbors, type-on-card editing, one placeholder block per gap, pending-tray "place from page N". ## Fix - Round the kebab backing on series cards (was a translucent square behind the round ⋮). CI green on dev (run 959). No new migrations in the Browse work; series numbering shipped its migration in an earlier dev push. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 4 commits 2026-06-12 00:14:26 -04:00
feat(series): operator-set sparse page numbers + gap blocks (#789 tweak)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 28s
CI / integration (push) Failing after 3m17s
013b9d7f06
Replaces the auto-renumbered 1..N position key with operator-OWNED page
numbers: sparse, gaps allowed, editable, never auto-renumbered. Order follows
the numbers; unnumbered pages sort to the tail. This is the fix for the model
that clobbered hand-set numbers on the flatten — numbers are now data, not a
derived sequence.

- series_service: drop the renumber-on-reorder/remove; order by page_number
  NULLS LAST; new set_page_number(image_id, n|None); list_pages returns `gaps`
  (one entry per missing-number run) + each pending group's parsed `start_page`;
  set_cover renumbers below the current min; place_pending(image_ids, start_page)
  numbers placed pages sequentially from the start (drop junk first → numbers
  line up); add_post stamps the parsed start on staged pages.
- api/tags: POST /series/<id>/pages/number (set one page's number); /pending/
  place takes start_page; removed /reorder.
- frontend: per-card editable number input; one gap block per gap with
  drop-on-edge to assign the adjacent number (middle → type); append drop zone;
  pending tray gets a "from page N" field + "Place from page N".
- tests reworked: sparse numbers + gaps, place-from-start, set-page-number route.

No migration; nothing destructive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(series): assert group start_page, not per-page stated_page
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 33s
CI / integration (push) Successful in 3m11s
3e22e78aa4
add_post now stamps the post's parsed START (constant) on every staged
pending page so the group start survives junk removal; list_pages
surfaces it as start_page. Update the stale per-page [9,10,11] assertion
to check grp["start_page"] == 9.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(series): round the kebab backing on series cards
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 35s
CI / backend-lint-and-test (push) Successful in 56s
CI / integration (push) Successful in 3m14s
90c68f8b2a
The tinted backing was set on the square .fc-kebab wrapper span while the
button is round, so a translucent square showed behind the round ⋮.
border-radius:50% makes the backing a circle matching the button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(browse): sticky tabs + per-tab search bar (server-side, scope-aware)
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 25s
CI / integration (push) Successful in 3m10s
2c544ad5af
The Browse tab nav scrolled away (operator didn't know it existed) and
Posts had no search. Roll the tab strip + a shared search field into one
sticky block pinned under the 64px TopNav.

- Posts gains server-side text search: PostFeedService.scroll()/around()
  + /api/posts accept q (ILIKE over post_title OR description), applied
  INSIDE the artist/platform WHERE so search stays scoped to the active
  filter. Scope shown as clearable chips next to the search field.
- Artists/Tags search consolidates into the sticky bar: their inner
  search boxes are removed; they react to route.query.q (q is deep-
  linkable, e.g. /browse?tab=posts&q=foo). Platform/kind filters stay.
- Posts empty state now distinguishes 'no matches' from 'no posts yet'.

Tests: posts q-search matches title|description and stays artist-scoped
(service); q passthrough (api).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bvandeusen merged commit 909fa37b15 into main 2026-06-12 00:14:31 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#98