What It Does
Global search across all content types using PostgreSQL’spg_trgm extension for fuzzy trigram matching.
User Flow
Type Query
Search input with typewriter placeholder animation cycling through phrases (“Classic Chrome recipes”, “Portrait photography”, “Street photography”, “Fujifilm X-T5”, etc.). Minimum 2 characters to trigger search. Debounced via
useDebounce → supabase.rpc('global_search', { p_query, p_type_filter, p_limit }).Filter by Type
Icon-only filter tabs appear once query ≥ 2 characters. Active tab has 2px bottom border.
Search Scopes
Four filter tabs, icon-only (matching profile tab style):| Tab | Icon | Content | View |
|---|---|---|---|
| Posts | ImageIcon | Posts only | Masonry grid |
| Recipes | Film | Recipes only | Masonry grid |
| Collections | LibraryBig | Collections only | Masonry grid |
| Creators | Users | User profiles | List view (CreatorCardList) |
typeFilter parameter is passed to the global_search RPC so it only scans the relevant table(s).
Empty & Loading States
- Before typing: centered
Searchicon (48px) + “Search for recipes, posts, collections, or creators” - Loading:
MasonryGridSkeletonwith 6 items - No results:
EmptyStatewith “No results found” / “We couldn’t find anything for [query]” - No results for specific tab:
EmptyStatewith “No [type]s match [query]“
Components
| Component | Purpose |
|---|---|
ContentCard | Recipe/post/collection results (masonry grid, variant="imageOnly") |
CreatorCard | Creator result in masonry grid |
CreatorCardList | Creator result in list view (avatar, name, follow button) |
VirtualizedMasonryGrid | Masonry layout for content results |
MasonryGridSkeleton | Loading skeleton |
EmptyState | No results state |
Context
SearchProvider (src/context/SearchContext.tsx) — manages search query state, results, filters. Also exposes openSearch(query) used by MetadataPills to navigate to search with a pre-filled query.
Hooks
useSearch(src/hooks/useSearch.ts) — search logicuseDebounce(src/hooks/useDebounce.ts) — debounces search input
Data Access Pattern
The mobile app calls Supabase directly —
supabase.rpc('global_search'). The web API route exists for the web client (Phase 2).Web API Route (Phase 2)
GET /api/search
- Query params:
q(search term),type(optional filter: ‘recipe’, ‘post’, ‘collection’, ‘user’) - Calls
global_searchRPC
RPC Functions
| Function | Parameters | Returns |
|---|---|---|
global_search | p_query (text), p_type_filter (optional), p_limit (30) | JSON — results across all content types |
check_username_available | p_username (text), p_exclude_user_id (optional) | boolean — used for registration and profile edit |
Database Extension
pg_trgm (installed in public schema) — provides trigram-based similarity matching for fuzzy search. Used by global_search RPC for % LIKE matching and similarity scoring.