12 KiB
12 KiB
NaviDocs Search Integration Status
Agent 10 Integration Report
Date: 2025-11-13 Task: Integrate Apple Preview-style search components into DocumentView.vue
Components Status
✅ Completed Components
-
SearchResultsSidebar.vue (
/home/setup/navidocs/client/src/components/SearchResultsSidebar.vue)- Status: EXISTS and COMPLETE
- Features:
- Slide-in sidebar from left
- Result list with thumbnails and snippets
- Page number indicators
- Current result highlighting
- Navigation footer showing "X of Y" results
- Close button
- Click handlers for result navigation
- Integration Point: Needs to be imported and added to DocumentView template
-
SearchSuggestions.vue (
/home/setup/navidocs/client/src/components/SearchSuggestions.vue)- Status: EXISTS and COMPLETE
- Features:
- Recent searches section with timestamps
- Suggested terms section
- Keyboard navigation (↑↓ for navigate, Enter for select, Esc to close)
- Clear history button
- Empty state
- Dropdown animation with proper positioning
- Integration Point: Needs to be imported and added to DocumentView template below search input
DocumentView.vue Current State
✅ Already Implemented
-
Search Infrastructure:
- ✅ Basic search input with debounced handler
- ✅ Search highlighting on current page
- ✅ Cross-page search functionality (
searchAllPages()) - ✅ Hit navigation (next/prev) with cross-page support
- ✅ Jump list for quick navigation
- ✅ Search statistics tracking
- ✅ Thumbnail cache for search results
- ✅ Apple Preview-style highlighting (yellow for all matches, pink for active)
- ✅ Scroll-to-match functionality
- ✅ Collapsed header state support
-
State Management:
// Current search state const searchQuery = ref(route.query.q || '') const searchInput = ref(route.query.q || '') const currentHitIndex = ref(0) const totalHits = ref(0) const hitList = ref([]) // Current page hits const allPagesHitList = ref([]) // All pages hits const jumpListOpen = ref(false) const isSearchingAllPages = ref(false) const searchStats = computed(() => { ... }) // Comprehensive stats -
Search Functions:
performSearch()- Main search executionclearSearch()- Clear all search statehandleSearchInput()- Debounced input handlerhighlightSearchTerms()- Highlight matches on current pageupdateHighlightsForCurrentPage()- Apple Preview-style highlightingscrollToHit()- Scroll to specific matchnextHit()/prevHit()- Navigate between matches (with cross-page support)jumpToHit()- Jump to specific match from listsearchAllPages()- Search entire document
Required Integration Steps
🔴 Step 1: Import Components
Add to imports section (around line 315-320):
import SearchResultsSidebar from '../components/SearchResultsSidebar.vue'
import SearchSuggestions from '../components/SearchSuggestions.vue'
🔴 Step 2: Add Search Suggestions Component
Add SearchSuggestions component in header section (around line 46-80), wrapping the search input:
<div class="flex-1" :class="isHeaderCollapsed ? 'max-w-2xl' : 'max-w-3xl mx-auto'">
<div class="relative group">
<input
ref="searchInputRef"
v-model="searchInput"
@keydown.enter="performSearch"
@input="handleSearchInput"
@focus="showSearchSuggestions = true"
@blur="hideSearchSuggestions"
type="text"
class="w-full px-6 pr-28 rounded-2xl border-2 border-white/20 bg-white/10 backdrop-blur-lg text-white placeholder-white/50 shadow-lg focus:outline-none focus:border-pink-400 focus:ring-4 focus:ring-pink-400/20"
:class="isHeaderCollapsed ? 'h-10 text-sm' : 'h-16 text-lg'"
placeholder="Search in document... (Cmd/Ctrl+F)"
/>
<!-- Add SearchSuggestions Here -->
<SearchSuggestions
:visible="showSearchSuggestions && searchInput.length > 0"
:history="searchHistory"
:suggestions="searchSuggestions"
:document-id="documentId"
@select="handleSuggestionSelect"
@clear-history="clearSearchHistory"
/>
<div class="absolute right-3 top-1/2 transform -translate-y-1/2 flex items-center gap-2">
<!-- ... existing buttons ... -->
</div>
</div>
</div>
🔴 Step 3: Add SearchResultsSidebar Component
Add SearchResultsSidebar after TOC sidebar (around line 229-237):
<!-- PDF Viewer with TOC Sidebar -->
<main class="viewer-wrapper relative">
<!-- TOC Sidebar -->
<TocSidebar
v-if="documentId"
:document-id="documentId"
:current-page="currentPage"
@navigate-to-page="handleTocJump"
/>
<!-- Search Results Sidebar -->
<SearchResultsSidebar
:visible="searchQuery && totalHits > 0"
:results="allPagesHitList.length > 0 ? allPagesHitList : hitList"
:current-index="currentHitIndex"
:search-term="searchQuery"
@result-click="jumpToHit"
@close="clearSearch"
/>
<!-- PDF Pane -->
<div class="pdf-pane py-8">
<!-- ... existing PDF viewer ... -->
</div>
</main>
🔴 Step 4: Add Required State Variables
Add these state variables (around line 350-355):
// Search suggestions state
const showSearchSuggestions = ref(false)
const searchHistory = ref([])
const searchSuggestions = ref([
'engine', 'electrical', 'plumbing', 'safety', 'maintenance',
'fuel', 'navigation', 'bilge', 'hull', 'propeller'
])
const searchInputRef = ref(null) // Reference to search input element
🔴 Step 5: Add Event Handlers
Add these handler functions (around line 760):
// Handle search suggestion selection
function handleSuggestionSelect(query) {
searchInput.value = query
showSearchSuggestions.value = false
performSearch()
// Add to search history
addToSearchHistory(query)
}
// Hide search suggestions with delay to allow click events
function hideSearchSuggestions() {
setTimeout(() => {
showSearchSuggestions.value = false
}, 200)
}
// Add search to history
function addToSearchHistory(query) {
const historyItem = {
query: query,
timestamp: Date.now(),
resultsCount: totalHits.value
}
// Remove duplicates
searchHistory.value = searchHistory.value.filter(item => item.query !== query)
// Add to beginning
searchHistory.value.unshift(historyItem)
// Limit to 10 items
if (searchHistory.value.length > 10) {
searchHistory.value = searchHistory.value.slice(0, 10)
}
// Save to localStorage
try {
localStorage.setItem(`navidocs-search-history-${documentId.value}`, JSON.stringify(searchHistory.value))
} catch (e) {
console.warn('Failed to save search history:', e)
}
}
// Clear search history
function clearSearchHistory() {
searchHistory.value = []
try {
localStorage.removeItem(`navidocs-search-history-${documentId.value}`)
} catch (e) {
console.warn('Failed to clear search history:', e)
}
}
// Load search history from localStorage
function loadSearchHistory() {
try {
const stored = localStorage.getItem(`navidocs-search-history-${documentId.value}`)
if (stored) {
searchHistory.value = JSON.parse(stored)
}
} catch (e) {
console.warn('Failed to load search history:', e)
}
}
🔴 Step 6: Add Keyboard Shortcuts
Add keyboard shortcut handler in onMounted() (around line 878-890):
onMounted(() => {
loadDocument()
loadSearchHistory() // Load search history on mount
// Handle deep links (#p=12)
const hash = window.location.hash
if (hash.startsWith('#p=')) {
const pageNum = parseInt(hash.substring(3), 10)
if (!Number.isNaN(pageNum) && pageNum >= 1) {
currentPage.value = pageNum
pageInput.value = pageNum
}
}
// Global keyboard shortcuts for search
const handleKeyboardShortcuts = (event) => {
// Cmd/Ctrl + F: Focus search input
if ((event.metaKey || event.ctrlKey) && event.key === 'f') {
event.preventDefault()
searchInputRef.value?.focus()
}
// Cmd/Ctrl + G: Next result
if ((event.metaKey || event.ctrlKey) && event.key === 'g' && !event.shiftKey) {
event.preventDefault()
if (totalHits.value > 0) {
nextHit()
}
}
// Cmd/Ctrl + Shift + G: Previous result
if ((event.metaKey || event.ctrlKey) && event.key === 'g' && event.shiftKey) {
event.preventDefault()
if (totalHits.value > 0) {
prevHit()
}
}
// Escape: Clear search
if (event.key === 'Escape' && searchQuery.value) {
clearSearch()
}
}
window.addEventListener('keydown', handleKeyboardShortcuts)
// ... existing scroll handlers ...
// Clean up keyboard listener
onBeforeUnmount(() => {
window.removeEventListener('keydown', handleKeyboardShortcuts)
// ... existing cleanup ...
})
})
Keyboard Shortcuts Summary
| Shortcut | Action |
|---|---|
Cmd/Ctrl + F |
Focus search input |
Enter |
Perform search |
Cmd/Ctrl + G |
Next match |
Cmd/Ctrl + Shift + G |
Previous match |
Escape |
Clear search |
↑ / ↓ (in suggestions) |
Navigate suggestions |
Enter (in suggestions) |
Select suggestion |
Testing Checklist
- Search input focuses on Cmd/Ctrl+F
- Search suggestions appear on focus with non-empty input
- Recent searches display with timestamps
- Clicking suggestion performs search
- Search highlights all matches (yellow) on current page
- Active match highlighted differently (pink)
- Next/Previous buttons work
- Cross-page navigation works (next/prev jumps to different pages)
- Search results sidebar shows all matches across all pages
- Clicking result in sidebar navigates to that page
- Search history persists in localStorage
- Clear history button works
- Keyboard shortcuts work as expected
- Header collapse/expand doesn't break search UI
- Mobile responsive (sidebars adjust properly)
Performance Considerations
- Debouncing: Consider adding debounced search-as-you-type
- Virtual Scrolling: For documents with 100s of matches, implement virtual scrolling in results sidebar
- Web Workers: Move
searchAllPages()to a Web Worker for non-blocking search - Thumbnail Generation: Generate thumbnails lazily as user scrolls through results
- Result Caching: Cache search results for recent queries
Future Enhancements
- Fuzzy Search: Add support for typo-tolerant search
- Search Filters: Filter by section, page range, or content type
- Search History Analytics: Track most searched terms
- Regex Support: Allow regex patterns in search
- Multi-term Search: AND/OR operators for complex queries
- Export Results: Export search results to CSV/JSON
- Search in Annotations: Include user annotations in search
Files Modified
/home/setup/navidocs/client/src/views/DocumentView.vue(partial - needs completion)
Files Created
/home/setup/navidocs/SEARCH_INTEGRATION_STATUS.md(this file)
Files Ready for Integration
/home/setup/navidocs/client/src/components/SearchResultsSidebar.vue✅/home/setup/navidocs/client/src/components/SearchSuggestions.vue✅
Next Steps
- Complete integration steps 1-6 above
- Test all functionality
- Fix any styling conflicts between TOC sidebar and Search sidebar
- Optimize cross-page search performance
- Add unit tests for search functions
- Add E2E tests for search workflows
Notes
- The existing search implementation in DocumentView.vue is quite comprehensive and handles cross-page search elegantly
- The two sidebar components (TOC and Search) may need z-index adjustments to avoid conflicts
- Consider adding a toggle to switch between TOC sidebar and Search sidebar if both are active
- SearchResultsSidebar uses fixed positioning on the left; TOC sidebar also uses left positioning - may need adjustment
- Apple Preview-style highlighting is already implemented (yellow for all, pink for active)
Contact
For questions about this integration, refer to:
- Original task specification (Agent 10 instructions)
- SearchResultsSidebar.vue source
- SearchSuggestions.vue source
- DocumentView.vue existing search implementation