navidocs/SEARCH_INTEGRATION_STATUS.md

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

  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:

    // 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):

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

  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