408 lines
12 KiB
Markdown
408 lines
12 KiB
Markdown
# 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
|
|
|
|
1. **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
|
|
|
|
2. **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
|
|
|
|
1. **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
|
|
|
|
2. **State Management:**
|
|
```javascript
|
|
// 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
|
|
```
|
|
|
|
3. **Search Functions:**
|
|
- `performSearch()` - Main search execution
|
|
- `clearSearch()` - Clear all search state
|
|
- `handleSearchInput()` - Debounced input handler
|
|
- `highlightSearchTerms()` - Highlight matches on current page
|
|
- `updateHighlightsForCurrentPage()` - Apple Preview-style highlighting
|
|
- `scrollToHit()` - Scroll to specific match
|
|
- `nextHit()` / `prevHit()` - Navigate between matches (with cross-page support)
|
|
- `jumpToHit()` - Jump to specific match from list
|
|
- `searchAllPages()` - Search entire document
|
|
|
|
---
|
|
|
|
## Required Integration Steps
|
|
|
|
### 🔴 Step 1: Import Components
|
|
|
|
Add to imports section (around line 315-320):
|
|
```javascript
|
|
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:
|
|
|
|
```vue
|
|
<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):
|
|
|
|
```vue
|
|
<!-- 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):
|
|
|
|
```javascript
|
|
// 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):
|
|
|
|
```javascript
|
|
// 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):
|
|
|
|
```javascript
|
|
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
|
|
|
|
1. **Debouncing:** Consider adding debounced search-as-you-type
|
|
2. **Virtual Scrolling:** For documents with 100s of matches, implement virtual scrolling in results sidebar
|
|
3. **Web Workers:** Move `searchAllPages()` to a Web Worker for non-blocking search
|
|
4. **Thumbnail Generation:** Generate thumbnails lazily as user scrolls through results
|
|
5. **Result Caching:** Cache search results for recent queries
|
|
|
|
---
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Fuzzy Search:** Add support for typo-tolerant search
|
|
2. **Search Filters:** Filter by section, page range, or content type
|
|
3. **Search History Analytics:** Track most searched terms
|
|
4. **Regex Support:** Allow regex patterns in search
|
|
5. **Multi-term Search:** AND/OR operators for complex queries
|
|
6. **Export Results:** Export search results to CSV/JSON
|
|
7. **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
|
|
|
|
1. Complete integration steps 1-6 above
|
|
2. Test all functionality
|
|
3. Fix any styling conflicts between TOC sidebar and Search sidebar
|
|
4. Optimize cross-page search performance
|
|
5. Add unit tests for search functions
|
|
6. 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
|