docs: add GIF category pills design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# GIF Category Pills Design
|
||||
|
||||
Horizontal scrollable row of category pills on the GIF picker's idle screen,
|
||||
letting users browse GIFs by emotion/reaction category.
|
||||
|
||||
## Context
|
||||
|
||||
The GIF picker currently shows featured/trending GIFs on the idle screen with a
|
||||
search input above. Users can type to search, but there's no way to browse by
|
||||
category. Threads shows a row of category pills (Trending, Love, Happy, Sad,
|
||||
etc.) that give quick access to common GIF reactions without typing.
|
||||
|
||||
## Decisions
|
||||
|
||||
| Question | Decision | Rationale |
|
||||
|----------|----------|-----------|
|
||||
| Layout | Horizontal scrollable pill row + featured grid below | Matches Threads pattern. Pills provide quick access, grid fills remaining space. |
|
||||
| Categories | Hardcoded curated list of 8 | Predictable, no extra API call, intentional selection of popular emotions. |
|
||||
| "Trending" pill | Uses existing featured endpoint | No search query needed — it's the default idle view. |
|
||||
| Category tap behavior | Sets search query to category's searchterm | Reuses existing `useGifPickerData` search path, no new data fetching logic. |
|
||||
| Pills while typing | Hide when input has text, reappear when cleared | Clean separation between browse and search modes. |
|
||||
|
||||
## Curated Categories
|
||||
|
||||
| Pill | Search term | Emoji |
|
||||
|------|------------|-------|
|
||||
| Trending | *(featured endpoint, no search)* | 🔥 |
|
||||
| Love | `love` | ❤️ |
|
||||
| Happy | `happy` | 😄 |
|
||||
| Sad | `cry` | 😢 |
|
||||
| Party | `congratulations` | 🎉 |
|
||||
| Yes | `yes` | 👍 |
|
||||
| LOL | `lol` | 😂 |
|
||||
| Excited | `excited` | 🤩 |
|
||||
|
||||
"Trending" is the default active pill when the dialog opens.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Component Tree
|
||||
|
||||
```
|
||||
GifPickerBody
|
||||
├─ GifPickerHeader
|
||||
│ └─ TextField.Input
|
||||
├─ GifCategoryPills ← NEW (hidden when typing)
|
||||
├─ GifPickerPlaceholder
|
||||
└─ GifPickerGrid
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
1. Dialog opens → "Trending" pill active → featured endpoint fires (existing)
|
||||
2. User taps a category pill → active pill updates → search query set to
|
||||
pill's `searchterm` → `useGifPickerData` fires the search endpoint
|
||||
3. User starts typing → pills hide → search query comes from text input
|
||||
4. User clears input → pills reappear → active pill resets to "Trending" →
|
||||
featured GIFs reload
|
||||
|
||||
### File Changes
|
||||
|
||||
**New files:**
|
||||
|
||||
- `src/features/gifPicker/components/GifCategoryPills.tsx` — horizontal
|
||||
scrollable row of pill buttons. Accepts `activeCategory`, `onSelectCategory`,
|
||||
and `visible` props. Each pill is a `Pressable` with emoji + label. The
|
||||
active pill gets a highlighted background. The component renders `null` when
|
||||
`visible` is false.
|
||||
|
||||
**Modified files:**
|
||||
|
||||
- `src/features/gifPicker/GifPickerDialog.tsx` — add `activeCategory` state to
|
||||
`GifPickerBody`. When a category is selected (and it's not "trending"), pass
|
||||
its searchterm as the search query to `useGifPickerData`. Render
|
||||
`GifCategoryPills` in the header area. Hide pills when `rawSearch.length > 0`.
|
||||
Reset `activeCategory` to "trending" when input is cleared.
|
||||
|
||||
## Interaction States
|
||||
|
||||
### 1. Idle — "Trending" active
|
||||
|
||||
Dialog just opened. "Trending" pill is highlighted. Featured GIFs show in the
|
||||
grid. Search input is empty.
|
||||
|
||||
### 2. Category selected
|
||||
|
||||
User tapped a category pill (e.g., "Happy"). That pill highlights, "Trending"
|
||||
unhighlights. Grid shows search results for "happy". Search input stays empty
|
||||
— the query comes from the pill, not the text field.
|
||||
|
||||
### 3. Typing — pills hidden
|
||||
|
||||
User started typing in the search input. The pill row hides entirely. Grid
|
||||
shows search results for whatever the user typed. The `activeCategory` state
|
||||
stays as-is (not reset) — it's just not visible or used while typing. This
|
||||
avoids unnecessary state churn; it only resets when the input is fully cleared.
|
||||
|
||||
### 4. Input cleared — pills return
|
||||
|
||||
User cleared the search input (backspace or clear button). Pills reappear with
|
||||
"Trending" active. Featured GIFs reload in the grid.
|
||||
|
||||
## Pill Styling
|
||||
|
||||
- Horizontal `ScrollView` with `horizontal` and `showsHorizontalScrollIndicator={false}`
|
||||
- Each pill: `Pressable` with `rounded_full`, emoji + text, theme-aware colors
|
||||
- Active pill: stronger background (`t.atoms.bg_contrast_100` or similar)
|
||||
- Inactive pill: subtle border (`t.atoms.border_contrast_low`)
|
||||
- Row has horizontal padding matching the GIF grid
|
||||
|
||||
## Scope Boundaries
|
||||
|
||||
**In scope:**
|
||||
- `GifCategoryPills` component with horizontal scroll
|
||||
- 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
|
||||
- "Trending" as default active pill (uses featured endpoint)
|
||||
|
||||
**Out of scope:**
|
||||
- Recent / Favorited pills (needs client-side persistence)
|
||||
- Dynamic categories from the `/v2/categories` API
|
||||
- Category GIF thumbnails on the pills
|
||||
- Animation for pills show/hide transition
|
||||
Reference in New Issue
Block a user