@@ -2,12 +2,13 @@ import { useState, useEffect, useCallback, useRef } from 'react'
22import { useParams , useNavigate , useSearchParams } from 'react-router-dom'
33import {
44 LuArrowLeft , LuChevronLeft , LuChevronRight , LuDownload ,
5- LuFileText , LuColumns2 , LuFile , LuSearch , LuList , LuBookmark , LuBookmarkPlus ,
5+ LuFileText , LuColumns2 , LuFile , LuSearch , LuList , LuBookmark , LuBookmarkPlus , LuHeart ,
66} from 'react-icons/lu'
77import api , { mediaUrl } from '../api'
88import Spinner from '../components/Spinner'
99import { getBookPrefs , saveBookPrefs , saveRecentBook } from '../hooks/useBookPrefs'
1010import { getUserPrefs } from '../hooks/useUserPrefs'
11+ import { useFavorites } from '../context/FavoritesContext'
1112import useReaderGestures from '../hooks/useReaderGestures'
1213import TocSidebar from '../components/reader/TocSidebar'
1314import SearchSidebar from '../components/reader/SearchSidebar'
@@ -72,6 +73,8 @@ export default function ReaderView() {
7273 const [ zoom , setZoom ] = useState ( 1 )
7374 const [ pan , setPan ] = useState ( { x : 0 , y : 0 } )
7475
76+ const { isFavorite, toggleFavorite } = useFavorites ( )
77+
7578 const directionRef = useRef ( 1 ) // 1 = forward, -1 = backward
7679 const axisRef = useRef ( 'x' ) // 'x' | 'y'
7780 const currentPageRef = useRef ( 1 ) // always tracks latest page without being a dep
@@ -225,19 +228,25 @@ export default function ReaderView() {
225228 if ( mode === 'spread' ) goToPage ( currentPage , 'spread' )
226229 } , [ mode ] ) // eslint-disable-line react-hooks/exhaustive-deps
227230
228- // Keyboard navigation
231+ // Keyboard navigation + shortcuts
229232 const step = mode === 'spread' ? ( currentPage === 1 ? 1 : 2 ) : 1
230233 useEffect ( ( ) => {
231234 const handleKeyDown = ( e ) => {
232- if ( mode === 'pdf' ) return
233- if ( e . key === 'ArrowLeft' ) { e . preventDefault ( ) ; goToPage ( currentPage - step , undefined , 'x' ) }
234- if ( e . key === 'ArrowRight' ) { e . preventDefault ( ) ; goToPage ( currentPage + step , undefined , 'x' ) }
235- if ( e . key === 'ArrowUp' ) { e . preventDefault ( ) ; goToPage ( currentPage - step , undefined , 'y' ) }
236- if ( e . key === 'ArrowDown' ) { e . preventDefault ( ) ; goToPage ( currentPage + step , undefined , 'y' ) }
235+ if ( e . target . tagName === 'INPUT' || e . target . tagName === 'TEXTAREA' ) return
236+ if ( mode !== 'pdf' ) {
237+ if ( e . key === 'ArrowLeft' ) { e . preventDefault ( ) ; goToPage ( currentPage - step , undefined , 'x' ) }
238+ if ( e . key === 'ArrowRight' ) { e . preventDefault ( ) ; goToPage ( currentPage + step , undefined , 'x' ) }
239+ if ( e . key === 'ArrowUp' ) { e . preventDefault ( ) ; goToPage ( currentPage - step , undefined , 'y' ) }
240+ if ( e . key === 'ArrowDown' ) { e . preventDefault ( ) ; goToPage ( currentPage + step , undefined , 'y' ) }
241+ }
242+ if ( e . key === 'f' ) toggleFavorite ( 'book' , bookId )
243+ if ( e . key === 't' ) togglePanel ( 'toc' )
244+ if ( e . key === 'b' ) togglePanel ( 'bookmarks' )
245+ if ( e . key === 's' ) togglePanel ( 'search' )
237246 }
238247 window . addEventListener ( 'keydown' , handleKeyDown )
239248 return ( ) => window . removeEventListener ( 'keydown' , handleKeyDown )
240- } , [ mode , currentPage , step , goToPage ] )
249+ } , [ mode , currentPage , step , goToPage , bookId , toggleFavorite ] )
241250
242251 const wheelNav = getUserPrefs ( ) . wheelNav !== false
243252
@@ -358,6 +367,14 @@ export default function ReaderView() {
358367
359368 < AddToCampaignButton resourceType = "book" resourceId = { bookId } />
360369
370+ < button
371+ onClick = { ( ) => toggleFavorite ( 'book' , bookId ) }
372+ title = { isFavorite ( 'book' , bookId ) ? 'Remove from favorites' : 'Add to favorites' }
373+ style = { { ...btnStyle , color : isFavorite ( 'book' , bookId ) ? 'var(--gold)' : 'var(--text-muted)' } }
374+ >
375+ < LuHeart size = { 14 } fill = { isFavorite ( 'book' , bookId ) ? 'var(--gold)' : 'none' } />
376+ </ button >
377+
361378 { /* Add bookmark action — separate from the panel toggle */ }
362379 { mode !== 'pdf' && (
363380 < button
0 commit comments