feat: implement search-first Bible navigator with touch optimization

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-11 19:21:10 +00:00
parent a688945df2
commit 66fd575ad5
3 changed files with 274 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
'use client'
import { useState, useEffect } from 'react'
import { Search, Close } from '@mui/icons-material'
import { Box, TextField, InputAdornment, Paper, List, ListItem, ListItemButton, Typography } from '@mui/material'
import { searchBooks, type SearchResult } from '@/lib/bible-search'
interface SearchNavigatorProps {
onNavigate: (bookId: number, chapter: number) => void
}
export function SearchNavigator({ onNavigate }: SearchNavigatorProps) {
const [query, setQuery] = useState('')
const [results, setResults] = useState<SearchResult[]>([])
const [isOpen, setIsOpen] = useState(false)
useEffect(() => {
if (query.trim()) {
setResults(searchBooks(query))
setIsOpen(true)
} else {
setResults([])
setIsOpen(false)
}
}, [query])
const handleSelect = (result: SearchResult) => {
onNavigate(result.bookId, result.chapter)
setQuery('')
setIsOpen(false)
}
return (
<Box sx={{ position: 'relative', width: '100%' }}>
<TextField
placeholder="Search Bible (e.g., Genesis 1, John 3:16)"
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => query && setIsOpen(true)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Search sx={{ color: 'text.secondary' }} />
</InputAdornment>
),
endAdornment: query && (
<InputAdornment position="end">
<Close
sx={{ cursor: 'pointer', color: 'text.secondary' }}
onClick={() => setQuery('')}
/>
</InputAdornment>
),
}}
sx={{
width: '100%',
'& .MuiOutlinedInput-root': {
fontSize: '0.95rem',
'@media (max-width: 600px)': {
fontSize: '1rem' // Larger on mobile to avoid zoom
}
}
}}
/>
{isOpen && results.length > 0 && (
<Paper
sx={{
position: 'absolute',
top: '100%',
left: 0,
right: 0,
zIndex: 10,
mt: 1,
maxHeight: 300,
overflow: 'auto'
}}
>
<List>
{results.map((result, idx) => (
<ListItem key={idx} disablePadding>
<ListItemButton onClick={() => handleSelect(result)}>
<Box>
<Typography variant="body2" fontWeight={500}>
{result.reference}
</Typography>
</Box>
</ListItemButton>
</ListItem>
))}
</List>
</Paper>
)}
</Box>
)
}