Files
bookhoard/web/src/docs.ts
T
john-okeefe a8920a8f6c Add dashboard redesign, custom section builder, and enhanced search functionality
Features:
- Complete dashboard redesign with improved UI components and layout
- Implement custom section builder for personalized book organization
- Add new events tracking system for user interactions
- Enhance search functionality with better static search.js
- Update TypeScript type definitions for API responses

Backend:
- Update Go dependencies in go.mod
- Add new frontend routes in router

Templates:
- Update admin and dashboard templates with new components

Frontend:
- Refactor analytics, collections, conflicts, and queue modules
- Add new documentation features in docs.ts
- Implement linking between books and collections
- Add toast notifications for user feedback
- Include placeholder book SVG asset

This commit consolidates multiple feature additions and improvements
across the entire stack including backend, templates, and frontend.
2026-02-25 16:56:10 -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 docsSearchTimeout: ReturnType<typeof setTimeout> | null = null;
searchInput.addEventListener('input', () => {
const query = searchInput.value.trim();
if (docsSearchTimeout) {
clearTimeout(docsSearchTimeout);
}
if (query.length < 2) {
searchResults.innerHTML = '';
searchResults.classList.add('hidden');
return;
}
docsSearchTimeout = 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;