diff --git a/.superpowers/brainstorm/71603-1776195983/content/category-design.html b/.superpowers/brainstorm/71603-1776195983/content/category-design.html deleted file mode 100644 index cb75e508b5..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/content/category-design.html +++ /dev/null @@ -1,167 +0,0 @@ -

GIF Category Pills — Full Design

-

Horizontal scrollable pill row on the idle GIF picker screen

- -
-

Interaction Flow

-
- -
-
-
1. Idle — "Trending" active
-
-
- 🔍 - Search GIFs -
-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
...
-
-
-
-
-
-
Featured GIFs
-
-
-
- -
-
-
2. "Happy" tapped
-
-
- 🔍 - Search GIFs -
-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
...
-
-
-
-
-
-
Search results for "happy"
-
-
-
- -
-
-
3. Typing — pills hidden
-
-
- 🔍 - sponge| -
-
-
-
-
-
-
-
-
-
-
-
Search results
-
-
-
-
-
- -
-

Architecture

-
-
Component & Data Flow
-
-
-
-
Component Tree
-
-
GifPickerBody
-
├─ GifPickerHeader
-
│ └─ TextField.Input
-
├─ GifCategoryPills ← NEW
-
(hidden when typing)
-
├─ GifPickerPlaceholder
-
└─ GifPickerGrid
-
-
-
-
Data Flow
-
-
1. Idle → "Trending" active → featured endpoint
-
2. Tap pill → set search to pill's searchterm
-
3. useGifPickerData sees search → fires GIF search
-
4. User types → pills hide, search takes over
-
5. User clears input → pills reappear, "Trending" resets
-
-
-
-
-
-
- -
-

File Changes

-
-
+ src/features/gifPicker/components/GifCategoryPills.tsx — pill row component
-
~ src/features/gifPicker/GifPickerDialog.tsx — add category state, render pills in header, connect to search
-
-
- -
-

Curated Categories

-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
😢 Sad
-
🎉 Party
-
👍 Yes
-
😂 LOL
-
🤩 Excited
-
-
- -
-

Key Design Decisions

-
-
No new API endpoint needed — tapping a category pill just sets the search query to the category's searchterm and uses the existing search flow
-
"Trending" = featured endpoint — the default active pill uses the existing featured GIFs, no search query
-
Pills hide while typing — simple visibility toggle based on whether rawSearch has content
-
Clearing input resets to Trending — pills reappear with "Trending" active again
-
Hardcoded category list — curated for quality, no extra API call needed
-
-
- -
-

Scope

-
-
-

In Scope

-
    -
  • GifCategoryPills component (horizontal scroll, active state)
  • -
  • 8 curated category pills with emoji + label
  • -
  • Tap pill → search GIFs for that category
  • -
  • Pills hide when typing, reappear when cleared
  • -
  • Active pill highlight styling
  • -
-
-
-

Out of Scope

-
    -
  • Recent / Favorited (needs client-side persistence)
  • -
  • Dynamic categories from API
  • -
  • Category GIF thumbnails on the pills
  • -
-
-
-
diff --git a/.superpowers/brainstorm/71603-1776195983/content/category-layout.html b/.superpowers/brainstorm/71603-1776195983/content/category-layout.html deleted file mode 100644 index 4cdcad7604..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/content/category-layout.html +++ /dev/null @@ -1,106 +0,0 @@ -

Category pills — where and how?

-

These appear on the idle/featured GIF screen, before the user starts typing

- -
-
-
A
-
-

Horizontal scrollable row of text pills

-

A single row of pill buttons below the search input. Scrolls horizontally. Compact, leaves maximum space for the GIF grid. Like how Threads does it.

-
-
Text pills — horizontal scroll
-
-
- 🔍 - Search GIFs -
-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
😢 Sad
-
🎉 Party
-
👍 Yes
-
😭 LOL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
B
-
-

Grid of GIF thumbnail tiles with labels

-

A 2-3 column grid of category tiles, each showing the category's preview GIF with a text label overlay. More visual, but takes up more space and replaces the featured GIFs initially.

-
-
GIF thumbnail grid
-
-
- 🔍 - Search GIFs -
-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
😢 Sad
-
🎉 Party
-
👍 Yes
-
-
-
-
-
- -
-
C
-
-

Horizontal pills + featured GIFs below (Threads-style)

-

Exactly like Threads: category pills as a scrollable row, with featured/trending GIFs filling the grid below. Tapping a pill replaces the grid with results for that category. Best of both worlds.

-
-
Pills + featured grid (Threads)
-
-
- 🔍 - Search GIFs -
-
-
🔥 Trending
-
❤️ Love
-
😄 Happy
-
😢 Sad
-
🎉 Party
-
👍 Yes
-
-
-
-
-
-
-
-
-
-
-
-
Featured / Trending GIFs
-
-
-
-
-
- -
-

My recommendation: Option C

-

Matches the Threads pattern exactly. Pills provide quick category access, the featured GIF grid fills the space below. "Trending" is the default selected pill, tapping another pill swaps the grid to that category's results. When the user starts typing, the pills hide and the search takes over.

-
diff --git a/.superpowers/brainstorm/71603-1776195983/content/waiting.html b/.superpowers/brainstorm/71603-1776195983/content/waiting.html deleted file mode 100644 index f92c257acc..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/content/waiting.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

Continuing in terminal...

-
\ No newline at end of file diff --git a/.superpowers/brainstorm/71603-1776195983/state/server-stopped b/.superpowers/brainstorm/71603-1776195983/state/server-stopped deleted file mode 100644 index 11ee5cd47e..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/state/server-stopped +++ /dev/null @@ -1 +0,0 @@ -{"reason":"owner process exited","timestamp":1776198924022} diff --git a/.superpowers/brainstorm/71603-1776195983/state/server.log b/.superpowers/brainstorm/71603-1776195983/state/server.log deleted file mode 100644 index 34250c0795..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/state/server.log +++ /dev/null @@ -1,6 +0,0 @@ -{"type":"server-started","port":53072,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:53072","screen_dir":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/71603-1776195983/content","state_dir":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/71603-1776195983/state"} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/71603-1776195983/content/category-layout.html"} -{"source":"user-event","type":"click","text":"C\n \n Horizontal pills + featured GIFs below (Threads-style)\n Exactly like Threads: category pills as a scrollable row, with featured/trending GIFs filling the grid below. Tapping a pill replaces the grid with results for that category. Best of both worlds.\n \n Pills + featured grid (Threads)\n \n \n 🔍\n Search GIFs\n \n \n 🔥 Trending\n ❤️ Love\n 😄 Happy\n 😢 Sad\n 🎉 Party\n 👍 Yes\n \n \n \n \n \n \n \n \n \n \n \n Featured / Trending GIFs","choice":"c","id":null,"timestamp":1776196240353} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/71603-1776195983/content/waiting.html"} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/71603-1776195983/content/category-design.html"} -{"type":"server-stopped","reason":"owner process exited"} diff --git a/.superpowers/brainstorm/71603-1776195983/state/server.pid b/.superpowers/brainstorm/71603-1776195983/state/server.pid deleted file mode 100644 index 9f961dcb59..0000000000 --- a/.superpowers/brainstorm/71603-1776195983/state/server.pid +++ /dev/null @@ -1 +0,0 @@ -71612 diff --git a/.superpowers/brainstorm/86663-1776187526/content/design-overview.html b/.superpowers/brainstorm/86663-1776187526/content/design-overview.html deleted file mode 100644 index 249253650e..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/content/design-overview.html +++ /dev/null @@ -1,173 +0,0 @@ -

GIF Autocomplete — Full Design

-

Inline search suggestions powered by Klipy's autocomplete endpoint

- -
-

Architecture Overview

-
-
Component & Data Flow
-
-
- -
-
Component Tree
-
-
GifPickerDialog
-
└─ GifPickerBody
-
├─ GifPickerHeader
-
│ ├─ TextField.Input (search box)
-
│ └─ GifAutocompleteSuggestions ← NEW
-
├─ GifPickerPlaceholder
-
└─ GifPickerGrid
-
-
- -
-
Data Flow
-
-
1. User types → rawSearch state
-
2. rawSearch throttled @ 200ms → autocomplete query
-
3. rawSearch throttled @ 500ms → GIF search query
-
4. Autocomplete response → suggestion strings
-
5. User taps suggestion → fills input + fires search
-
6. Suggestions hide when input matches a selected term
-
-
-
-
-
-
- -
-

New Files

-
-
+ src/lib/constants.ts — add GIF_KLIPY_AUTOCOMPLETE endpoint
-
+ src/state/queries/klipy.ts — add useKlipyAutocompleteQuery hook
-
+ src/features/gifPicker/hooks/useGifAutocomplete.ts — orchestration hook (throttle + query + keyboard state)
-
+ src/features/gifPicker/components/GifAutocompleteSuggestions.tsx — inline suggestion list UI
-
~ src/features/gifPicker/components/GifPickerHeader.tsx — render suggestions below input
-
~ src/features/gifPicker/GifPickerDialog.tsx — wire up autocomplete state
-
-
- -
-

Interaction Flow

-
- -
-
-
1. Idle — no suggestions
-
-
- 🔍 - Search GIFs -
-
-
-
-
-
Featured GIFs
-
-
-
- -
-
-
2. Typing — suggestions appear
-
-
- 🔍 - hap| -
-
-
- 🔍 happy birthday -
-
- 🔍 happy -
-
- 🔍 happy easter -
-
-
-
-
-
-
-
-
- -
-
-
3. Selected — GIFs load
-
-
- 🔍 - happy birthday - -
-
-
-
-
-
-
-
-
-
-
-
Results for "happy birthday"
-
-
-
-
-
- -
-

Keyboard Navigation (Web)

-
-
ArrowDown / ArrowUp — move active highlight through suggestions
-
Enter — select highlighted suggestion (fills input, fires search)
-
Escape — dismiss suggestions (existing behavior closes dialog)
-
Continue typing — resets active index to 0, re-fetches suggestions
-
-

- ARIA: input gets role="combobox" + aria-controls, list gets role="listbox", - items get role="option" + aria-selected. ~30 lines of onKeyDown handling on web only. -

-
- -
-

Visibility Rules

-
-
SHOW when: rawSearch.length ≥ 1 AND suggestions.length > 0 AND user hasn't just selected a suggestion
-
HIDE when: rawSearch is empty OR user selected a suggestion OR user clears input
-
RE-SHOW when: user edits the input after a selection (e.g., backspace to modify)
-
-
- -
-

Scope Boundaries

-
-
-

In Scope

-
    -
  • Klipy autocomplete endpoint integration
  • -
  • Inline suggestion list in GifPickerHeader
  • -
  • 200ms throttle for autocomplete, independent of 500ms search throttle
  • -
  • Keyboard navigation on web (arrow keys, enter, escape)
  • -
  • ARIA accessibility attributes
  • -
  • Tap-to-select on native
  • -
-
-
-

Out of Scope

-
    -
  • Tenor autocomplete (Klipy only)
  • -
  • Trending/popular suggestions on empty input
  • -
  • Search history / recents
  • -
  • Categories or tag browsing
  • -
-
-
-
diff --git a/.superpowers/brainstorm/86663-1776187526/content/suggestion-placement.html b/.superpowers/brainstorm/86663-1776187526/content/suggestion-placement.html deleted file mode 100644 index 1d205da11c..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/content/suggestion-placement.html +++ /dev/null @@ -1,149 +0,0 @@ -

Where should autocomplete suggestions appear?

-

As you type in the GIF search box, where do completion suggestions show up?

- -
-
-
A
-
-

Inline list below the search input

-

Suggestions render as a vertical list between the search bar and the GIF grid. Tapping a suggestion fills the search field and triggers a GIF search. Simple, no z-index or portal concerns inside the dialog.

-
-
GIF Dialog — Inline Suggestions
-
-
-
- 🔍 - hap| -
-
-
-
- 🔍 happy birthday -
-
- 🔍 happy -
-
- 🔍 happy easter -
-
- 🔍 happy dance -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
B
-
-

Horizontal chips below the search input

-

Suggestions render as a scrollable row of pill/chip buttons. Compact, leaves more vertical space for the GIF grid. Common in mobile search UIs (YouTube, Google Images).

-
-
GIF Dialog — Chip Suggestions
-
-
-
- 🔍 - hap| -
-
-
-
happy birthday
-
happy
-
happy easter
-
happy dance
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
C
-
-

Sift popover dropdown (like Composer autocomplete)

-

Uses the @bsky.app/sift library to show a positioned popover below the input, matching how @mentions work in the Composer. Keyboard navigable on web. Needs Portal/z-index verification inside the dialog.

-
-
GIF Dialog — Sift Popover
-
-
-
-
- 🔍 - hap| -
-
-
-
- 🔍 happy birthday -
-
- 🔍 happy -
-
- 🔍 happy easter -
-
- 🔍 happy dance -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-

My recommendation: Option A (inline list)

-
-
-

Why A

-
    -
  • No Portal/z-index issues inside the bottom sheet (native) or modal (web)
  • -
  • Naturally fits the reserved slot in GifPickerHeader ("future: tabs render here")
  • -
  • Clear visual hierarchy — suggestions push the grid down, making them prominent
  • -
  • Simple to implement — just a conditional list render
  • -
-
-
-

Tradeoffs

-
    -
  • Takes more vertical space than chips (B) when visible
  • -
  • Doesn't reuse Sift (C), but that's OK — Sift solves cursor-anchored popovers which we don't need here
  • -
-
-
-
diff --git a/.superpowers/brainstorm/86663-1776187526/content/waiting.html b/.superpowers/brainstorm/86663-1776187526/content/waiting.html deleted file mode 100644 index f92c257acc..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/content/waiting.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

Continuing in terminal...

-
\ No newline at end of file diff --git a/.superpowers/brainstorm/86663-1776187526/state/server-stopped b/.superpowers/brainstorm/86663-1776187526/state/server-stopped deleted file mode 100644 index 62e9f8dbcb..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/state/server-stopped +++ /dev/null @@ -1 +0,0 @@ -{"reason":"idle timeout","timestamp":1776191006962} diff --git a/.superpowers/brainstorm/86663-1776187526/state/server.log b/.superpowers/brainstorm/86663-1776187526/state/server.log deleted file mode 100644 index 654405ece0..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/state/server.log +++ /dev/null @@ -1,5 +0,0 @@ -{"type":"server-started","port":49342,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:49342","screen_dir":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/86663-1776187526/content","state_dir":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/86663-1776187526/state"} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/86663-1776187526/content/suggestion-placement.html"} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/86663-1776187526/content/waiting.html"} -{"type":"screen-added","file":"/Users/pope/dev/bsky/social-app/.superpowers/brainstorm/86663-1776187526/content/design-overview.html"} -{"type":"server-stopped","reason":"idle timeout"} diff --git a/.superpowers/brainstorm/86663-1776187526/state/server.pid b/.superpowers/brainstorm/86663-1776187526/state/server.pid deleted file mode 100644 index 9b16ab7077..0000000000 --- a/.superpowers/brainstorm/86663-1776187526/state/server.pid +++ /dev/null @@ -1 +0,0 @@ -86672