Add search functionality to version and book dropdowns

- Replace Select components with Autocomplete for enhanced UX
- Add real-time search for bible versions (1400+ options)
- Enable book search by name or testament
- Improve version display format: "Name - Abbreviation"
- Add rich option rendering with metadata (language, chapters)
- Include smart filtering across multiple fields
- Maintain keyboard navigation and accessibility
- Fix header visibility issue in full screen mode

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-24 13:05:22 +00:00
parent ebd2519974
commit 6329ad0618
2 changed files with 96 additions and 44 deletions

View File

@@ -44,7 +44,8 @@ import {
FormControl,
InputLabel,
Select,
Container
Container,
Autocomplete
} from '@mui/material'
import {
Menu as MenuIcon,
@@ -703,36 +704,56 @@ export default function BibleReaderNew() {
{/* Version Selection */}
<Box sx={{ flex: { xs: '1 1 100%', sm: '1 1 auto' }, minWidth: { sm: 180, md: 200 } }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<FormControl fullWidth size="small">
<InputLabel>{t('version')}</InputLabel>
<Select
value={selectedVersion}
label={t('version')}
onChange={(e) => {
setSelectedVersion(e.target.value)
<Autocomplete
size="small"
fullWidth
value={versions.find(v => v.id === selectedVersion) || null}
onChange={(event, newValue) => {
if (newValue) {
setSelectedVersion(newValue.id)
// Reset to first book when version changes
if (books.length > 0) {
setSelectedBook(books[0].id)
setSelectedChapter(1)
updateUrl(books[0].id, 1, e.target.value)
updateUrl(books[0].id, 1, newValue.id)
}
}
}}
options={versions}
getOptionLabel={(option) => `${option.name} - ${option.abbreviation}`}
renderInput={(params) => (
<TextField
{...params}
label={t('version')}
placeholder="Search versions..."
/>
)}
renderOption={(props, option) => (
<Box component="li" {...props}>
<Box>
<Typography variant="body2" sx={{ fontWeight: 'medium' }}>
{option.name}
</Typography>
<Typography variant="caption" color="text.secondary">
{option.abbreviation} {option.language.toUpperCase()}
</Typography>
</Box>
</Box>
)}
disabled={versionsLoading}
MenuProps={{
PaperProps: {
style: {
maxHeight: 400,
},
},
loading={versionsLoading}
filterOptions={(options, { inputValue }) => {
const filtered = options.filter((option) =>
option.name.toLowerCase().includes(inputValue.toLowerCase()) ||
option.abbreviation.toLowerCase().includes(inputValue.toLowerCase()) ||
option.language.toLowerCase().includes(inputValue.toLowerCase())
)
return filtered
}}
>
{versions.map((version) => (
<MenuItem key={version.id} value={version.id}>
{version.abbreviation} - {version.name} ({version.language.toUpperCase()})
</MenuItem>
))}
</Select>
</FormControl>
ListboxProps={{
style: { maxHeight: 400 }
}}
/>
<Tooltip title={showAllVersions ? 'Show language versions only' : 'Show all versions'}>
<IconButton
size="small"
@@ -747,24 +768,48 @@ export default function BibleReaderNew() {
{/* Books Selection */}
<Box sx={{ flex: { xs: '1 1 100%', sm: '1 1 auto' }, minWidth: { sm: 200, md: 250 } }}>
<FormControl fullWidth size="small">
<InputLabel>{t('book')}</InputLabel>
<Select
value={selectedBook}
label={t('book')}
onChange={(e) => {
setSelectedBook(e.target.value)
<Autocomplete
size="small"
fullWidth
value={books.find(b => b.id === selectedBook) || null}
onChange={(event, newValue) => {
if (newValue) {
setSelectedBook(newValue.id)
setSelectedChapter(1)
updateUrl(e.target.value, 1, selectedVersion)
updateUrl(newValue.id, 1, selectedVersion)
}
}}
>
{books.map((book) => (
<MenuItem key={book.id} value={book.id}>
{book.name}
</MenuItem>
))}
</Select>
</FormControl>
options={books}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField
{...params}
label={t('book')}
placeholder="Search books..."
/>
)}
renderOption={(props, option) => (
<Box component="li" {...props}>
<Box>
<Typography variant="body2" sx={{ fontWeight: 'medium' }}>
{option.name}
</Typography>
<Typography variant="caption" color="text.secondary">
{option.testament} {option.chapters?.length || 0} chapters
</Typography>
</Box>
</Box>
)}
filterOptions={(options, { inputValue }) => {
return options.filter((option) =>
option.name.toLowerCase().includes(inputValue.toLowerCase()) ||
option.testament.toLowerCase().includes(inputValue.toLowerCase())
)
}}
ListboxProps={{
style: { maxHeight: 300 }
}}
/>
</Box>
{/* Chapter Selection */}

View File

@@ -28,12 +28,19 @@ body {
}
/* Bible Reader Full Screen Mode - Hide only site-level elements */
.bible-fullscreen-mode .MuiAppBar-root:first-child,
.bible-fullscreen-mode header,
.bible-fullscreen-mode nav,
.bible-fullscreen-mode .MuiAppBar-root,
.bible-fullscreen-mode footer,
.bible-fullscreen-mode [data-floating-chat="true"] {
display: none !important;
}
/* Exception: Keep bible reader's internal navigation visible */
.bible-fullscreen-mode .MuiContainer-root .MuiPaper-root {
display: block !important;
}
.bible-fullscreen-mode {
overflow: auto;
}