Files
bookhoard/web/src/docs.ts
T
john-okeefe dfd9cbcde7 feat(typescript): add feature modules for template conversion
- Add search.ts - header search with keyboard navigation
  - Debounced search with 300ms delay
  - Arrow key navigation through results
  - Escape to close, Enter to select
  - Library type icons and highlighting

- Add collections.ts - collection and rule management
  - Rule CRUD operations (create, update, delete)
  - Rule testing functionality
  - Bulk collection operations

- Add bookshelf.ts - book display and navigation
  - Library selection state management
  - Book viewing interactions
  - Pagination logic

- Add linking.ts - book matching and manual linking
  - Search and match functionality
  - Manual link modal
  - Bulk auto-link and suggestions

- Add api-explorer.ts - API testing interface
  - Request/response display
  - cURL command generation
  - History tracking

- Add admin.ts - admin dashboard actions
  - Library scan triggers
  - System statistics display
  - Profile management

- Add analytics.ts - analytics data loading
  - Chart.js integration
  - Daily reading minutes chart
  - Device usage and popular books display

- Add queue.ts - sync queue management
  - Process pending items
  - Clear failed/all items
  - Filter by status, type, device

- Add conflicts.ts - conflict resolution
  - Individual and bulk resolve operations
  - Winner device selection
  - Manual override inputs

- Add docs.ts - documentation search
  - Lunr.js search integration
  - Sidebar toggle for mobile
2026-02-18 16:40:51 -05:00

87 lines
2.9 KiB
TypeScript

function toggleSidebar(): void {
const sidebar = document.getElementById('docs-sidebar');
const overlay = document.getElementById('docs-overlay');
if (sidebar && overlay) {
sidebar.classList.toggle('translate-x-0');
sidebar.classList.toggle('-translate-x-full');
overlay.classList.toggle('hidden');
}
}
function initializeDocsSearch(): void {
const searchInput = document.getElementById('docs-search') as HTMLInputElement;
const searchResults = document.getElementById('docs-search-results');
if (!searchInput || !searchResults) return;
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
searchInput.addEventListener('input', () => {
const query = searchInput.value.trim();
if (searchTimeout) {
clearTimeout(searchTimeout);
}
if (query.length < 2) {
searchResults.innerHTML = '';
searchResults.classList.add('hidden');
return;
}
searchTimeout = setTimeout(() => {
performDocsSearch(query);
}, 300);
});
}
function performDocsSearch(query: string): void {
const searchResults = document.getElementById('docs-search-results');
if (!searchResults) return;
if (!(window as any).lunr) {
console.warn('Lunr.js not loaded');
return;
}
try {
const idx = (window as any).lunrIndex;
if (!idx) {
searchResults.innerHTML = '<p class="p-2 text-sm" style="color: var(--text-secondary)">Search index not loaded</p>';
searchResults.classList.remove('hidden');
return;
}
const results = idx.search(query);
if (results.length === 0) {
searchResults.innerHTML = '<p class="p-2 text-sm" style="color: var(--text-secondary)">No results found</p>';
} else {
searchResults.innerHTML = results.slice(0, 10).map((result: { ref: string }) => {
const doc = (window as any).docsData?.[result.ref];
if (!doc) return '';
return `
<a href="${result.ref}" class="block p-2 hover:bg-opacity-50 transition-colors" style="background-color: var(--bg-secondary)">
<p class="font-medium text-sm" style="color: var(--text-primary)">${doc.title || result.ref}</p>
${doc.section ? `<p class="text-xs" style="color: var(--text-secondary)">${doc.section}</p>` : ''}
</a>
`;
}).join('');
}
searchResults.classList.remove('hidden');
} catch (error) {
console.error('Search error:', error);
searchResults.innerHTML = '<p class="p-2 text-sm" style="color: var(--text-secondary)">Search error</p>';
searchResults.classList.remove('hidden');
}
}
document.addEventListener('DOMContentLoaded', () => {
initializeDocsSearch();
});
(window as any).toggleSidebar = toggleSidebar;