# Mobile Book Search & Discovery — Spec ## Overview Enhance the existing book search experience with mobile-first features: voice search via the Web Speech API, real-time autocomplete suggestions, and touch-optimized responsive layout. ## Prerequisites - Backend endpoints already exist (from `docs/backend/search-discovery-spec.md`): - `GET /api/books/?q=...&genre=...&author=...&reading_status=...` — paginated search - `GET /api/books/{id}/` — book detail - `GET /api/books/genres/` — genre discovery - `GET /api/books/authors/` — author discovery - Frontend `LibraryPage` and `BookDetailPage` components exist but lacked API client methods and types (fixed in this PR). ## Frontend API Client Additions ### `frontend/src/types/book.ts` — New exports ```typescript export interface BookSearchParams { q?: string; genre?: string; author?: string; reading_status?: string; ordering?: string; page?: number; page_size?: number; } export const READING_STATUS_OPTIONS: { value: string; label: string }[] = [ { value: "", label: "All Statuses" }, { value: "want_to_read", label: "Want to Read" }, { value: "reading", label: "Reading" }, { value: "finished", label: "Finished" }, { value: "dnf", label: "Did Not Finish" }, ]; ``` ### `frontend/src/api/books.ts` — New methods on `booksApi` | Method | Endpoint | Returns | |--------|----------|---------| | `searchBooks(params)` | `GET /api/books/` | `{ count, results: BookListItem[] }` | | `getBook(id)` | `GET /api/books/{id}/` | `BookDetail` | | `getGenres()` | `GET /api/books/genres/` | `string[]` | | `getAuthors()` | `GET /api/books/authors/` | `string[]` | ## Mobile Features ### 1. Voice Search - **Hook**: `useVoiceSearch` in `frontend/src/hooks/useVoiceSearch.ts` - Uses the Web Speech API (`SpeechRecognition` / `webkitSpeechRecognition`) - Returns: `{ isListening, transcript, isSupported, startListening, stopListening, hasError }` - Renders a microphone icon button next to the search input - On mobile, tapping the mic icon triggers the native speech recognition prompt - On success, populates the search input with the transcript and triggers a search - Graceful degradation: if SpeechRecognition API is unavailable, the mic button is hidden ### 2. Real-Time Suggestions (Autocomplete) - Component: `SearchSuggestions` rendered as a dropdown below the search input - On each keystroke (debounced 200ms), fetches `GET /api/books/?q=...&page_size=5` for suggestions - Shows up to 5 book title/author suggestions in a styled dropdown list - Clicking a suggestion navigates directly to `/books/{id}` - Clicking outside or pressing Escape dismisses the dropdown - Combines with existing full search results — suggestions are fast previews, not the main result list ### 3. Mobile-Responsive Enhancements - Filters panel is **collapsed by default** on mobile, toggleable via a "Filters" button - Touch targets minimum 44px (WCAG 2.1) - Results grid switches to **single column** below 600px viewport width - Search input and filters panel stack vertically on small screens - Add CSS breakpoints via inline styles and a `useMediaQuery` hook - Bottom navigation-style action buttons on mobile (Add Book, Bookmarks, Settings become icon-only) ## Component Hierarchy ``` LibraryPage ├── Header (title, count, action buttons) ├── SearchInput │ ├── TextInput (debounced 300ms) │ ├── VoiceSearchButton (microphone icon) │ └── SearchSuggestions (dropdown, debounced 200ms) ├── FiltersButton (mobile: toggle; desktop: always visible) ├── FiltersPanel (collapsible on mobile) │ ├── GenreSelect │ ├── AuthorSelect │ ├── StatusSelect │ └── ClearFiltersButton ├── LoadingState (skeleton grid) ├── ErrorState (message + retry button) ├── EmptyState (no results / no books) └── ResultsGrid (responsive: auto-fill vs single column) ``` ## Mobile-First CSS Strategy - Use inline styles with `@media` queries in a shared `breakpoints.ts` utility - Breakpoints: sm = 480px, md = 768px, lg = 1024px - Base styles are mobile-first (single column, full width) - Media queries expand to multi-column grid and horizontal layout on larger screens