diff --git a/backend/app/api/posts.py b/backend/app/api/posts.py index 9a3edb2..90d3fe5 100644 --- a/backend/app/api/posts.py +++ b/backend/app/api/posts.py @@ -17,6 +17,7 @@ async def list_posts(): cursor = args.get("cursor") or None artist_id_raw = args.get("artist_id") platform = args.get("platform") or None + q = (args.get("q") or "").strip() or None limit_raw = args.get("limit", "24") direction = args.get("direction", "older") around_raw = args.get("around") @@ -56,7 +57,7 @@ async def list_posts(): if around_id is not None: result = await svc.around( post_id=around_id, artist_id=artist_id, - platform=platform, limit=limit, + platform=platform, q=q, limit=limit, ) if result is None: return _bad("not_found", status=404, detail=f"post id={around_id}") @@ -64,7 +65,7 @@ async def list_posts(): try: page = await svc.scroll( cursor=cursor, artist_id=artist_id, - platform=platform, limit=limit, direction=direction, + platform=platform, q=q, limit=limit, direction=direction, ) except ValueError as exc: # Service raises ValueError for malformed cursors only; diff --git a/backend/app/services/post_feed_service.py b/backend/app/services/post_feed_service.py index a4e1f78..f83d0f0 100644 --- a/backend/app/services/post_feed_service.py +++ b/backend/app/services/post_feed_service.py @@ -45,6 +45,7 @@ class PostFeedService: cursor: str | None = None, artist_id: int | None = None, platform: str | None = None, + q: str | None = None, limit: int = 24, direction: str = "older", ) -> dict: @@ -52,7 +53,12 @@ class PostFeedService: time (default, infinite-scroll down); direction='newer' walks forward (scroll up in an anchored view). Items are always returned in feed (descending) order; `next_cursor` points to the far edge in the - requested direction (null when exhausted).""" + requested direction (null when exhausted). + + `q` is a free-text filter (ILIKE substring over post_title OR + description) applied INSIDE the artist/platform scope, so a search + from the Browse bar stays within whatever artist is filtered in + view (operator-asked 2026-06-11).""" if limit < 1 or limit > 100: raise ValueError("limit must be between 1 and 100") if direction not in ("older", "newer"): @@ -74,6 +80,12 @@ class PostFeedService: stmt = stmt.where(Post.artist_id == artist_id) if platform is not None: stmt = stmt.where(Source.platform == platform) + if q: + like = f"%{q}%" + stmt = stmt.where(or_( + Post.post_title.ilike(like), + Post.description.ilike(like), + )) if cursor: cur_ts, cur_id = decode_cursor(cursor) if direction == "older": @@ -124,6 +136,7 @@ class PostFeedService: post_id: int, artist_id: int | None = None, platform: str | None = None, + q: str | None = None, limit: int = 12, ) -> dict | None: """A window centered on `post_id`: up to `limit` newer posts + the @@ -143,11 +156,11 @@ class PostFeedService: older = await self.scroll( cursor=anchor_cursor, artist_id=artist_id, platform=platform, - limit=limit, direction="older", + q=q, limit=limit, direction="older", ) newer = await self.scroll( cursor=anchor_cursor, artist_id=artist_id, platform=platform, - limit=limit, direction="newer", + q=q, limit=limit, direction="newer", ) thumbs_map = await self._thumbnails_for([anchor_post.id]) atts_map = await self._attachments_for([anchor_post.id]) diff --git a/frontend/src/stores/posts.js b/frontend/src/stores/posts.js index ab3c766..cfdf6e8 100644 --- a/frontend/src/stores/posts.js +++ b/frontend/src/stores/posts.js @@ -11,7 +11,7 @@ export const usePostsStore = defineStore('posts', () => { const cursor = ref(null) const { loading, error, run } = useAsyncAction() const done = ref(false) - const filters = ref({ artist_id: null, platform: null }) + const filters = ref({ artist_id: null, platform: null, q: null }) // In-context (anchored) view: bidirectional cursors so the feed can load // newer posts on scroll-up and older posts on scroll-down around a post. @@ -32,6 +32,7 @@ export const usePostsStore = defineStore('posts', () => { if (cursor.value) q.cursor = cursor.value if (filters.value.artist_id != null) q.artist_id = filters.value.artist_id if (filters.value.platform) q.platform = filters.value.platform + if (filters.value.q) q.q = filters.value.q return q } @@ -47,6 +48,7 @@ export const usePostsStore = defineStore('posts', () => { filters.value = { artist_id: newFilters?.artist_id ?? null, platform: newFilters?.platform ?? null, + q: newFilters?.q ?? null, } _reset() await loadMore() @@ -78,6 +80,7 @@ export const usePostsStore = defineStore('posts', () => { const p = { ...extra } if (filters.value.artist_id != null) p.artist_id = filters.value.artist_id if (filters.value.platform) p.platform = filters.value.platform + if (filters.value.q) p.q = filters.value.q return p } @@ -93,6 +96,7 @@ export const usePostsStore = defineStore('posts', () => { filters.value = { artist_id: newFilters?.artist_id ?? null, platform: newFilters?.platform ?? null, + q: newFilters?.q ?? null, } loading.value = true error.value = null diff --git a/frontend/src/views/ArtistsView.vue b/frontend/src/views/ArtistsView.vue index f5582f3..e03786f 100644 --- a/frontend/src/views/ArtistsView.vue +++ b/frontend/src/views/ArtistsView.vue @@ -1,12 +1,9 @@