// search.js - Complete MiniSearch implementation with resources and scores import { sampleResources } from '../data/resources.js'; import { areasData } from '../data/areas.js'; let miniSearch, miniSearchResources; let allArtifacts; // no longer needs to be explicitly defined // Helper to create and populate a MiniSearch instance function createMiniSearchIndex(data, storeFields) { const search = new MiniSearch({ fields: ['title', 'description', 'areas', 'topics'], storeFields: storeFields }); search.addAll(data); return search; } // Initialize search export async function initializeSearch(artifactsData) { // Assign the passed artifactsData to allArtifacts allArtifacts = artifactsData; // The fetch for artifacts.json is removed from here since it's now loaded in main.js // Prepare data for MiniSearch const searchData = allArtifacts.map((artifact, index) => ({ id: index, title: artifact.title, description: artifact.description, type: artifact.type, areas: (artifact.areas || []).join(' '), topics: (artifact.topics || []).join(' '), url: artifact.url, date: artifact.date })); // Prepare resources data const resourcesData = sampleResources.map((resource, index) => ({ id: index, title: resource.title, description: resource.description, type: resource.type, areas: (resource.areaTags || []).join(' '), topics: (resource.subAreaTags || []).join(' '), url: resource.url, date: resource.date })); // Initialize MiniSearch for artifacts miniSearch = createMiniSearchIndex(searchData, ['title', 'description', 'type', 'areas', 'topics', 'url', 'date']); // Initialize MiniSearch for resources miniSearchResources = createMiniSearchIndex(resourcesData, ['title', 'description', 'type', 'areas', 'topics', 'url', 'date']); } export function searchContent(query) { if (!query || query.trim().length < 2) { return { artifacts: [], resources: [] }; } const artifactResults = miniSearch.search(query, { prefix: true, fuzzy: 0.2, boost: { title: 2, description: 1 } }); const resourceResults = miniSearchResources.search(query, { prefix: true, fuzzy: 0.2, boost: { title: 2, description: 1 } }); return { artifacts: artifactResults, // Show all results, not limited to 5 resources: resourceResults }; } // Helper functions function getAreaDisplayName(area) { return areasData[area]?.title || area; } function getSubAreaDisplayName(areaId, subArea) { const area = areasData[areaId]; if (!area || !area.subAreas) return subArea; const subAreaData = area.subAreas[subArea]; return typeof subAreaData === 'string' ? subAreaData : subAreaData?.name || subArea; } // Search UI export function initializeSearchUI(artifactsData) { initializeSearch(artifactsData).then(() => { console.log('Search initialized'); }); const searchInput = document.getElementById('search-input'); const searchResults = document.getElementById('search-results'); if (!searchInput || !searchResults) return; let searchTimeout; // Function to perform search function performSearch() { const query = searchInput.value.trim(); if (query.length < 2) { searchResults.innerHTML = `

Enter a search term...

`; return; } const results = searchContent(query); displaySearchResults(results, query); } // Handle input events (typing) searchInput.addEventListener('input', (e) => { clearTimeout(searchTimeout); const query = e.target.value.trim(); if (query.length < 2) { searchResults.innerHTML = `

Enter a search term...

`; return; } // Debounce search searchTimeout = setTimeout(() => { performSearch(); }, 300); }); // Handle Enter key (immediate search) searchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); clearTimeout(searchTimeout); performSearch(); } }); } // Update the displaySearchResults function in search.js export function displaySearchResults(results, query) { const { artifacts, resources } = results; const totalResults = artifacts.length + resources.length; if (totalResults === 0) { document.getElementById('search-results').innerHTML = `

No results found for "${query}"

`; return; } let html = `
Found ${totalResults} results (${artifacts.length} writings, ${resources.length} resources)
`; // Display artifacts with collapsible header if (artifacts.length > 0) { html += `
`; artifacts.forEach(result => { const score = Math.round(result.score * 100); // Create area links const areaLinks = result.areas ? result.areas.split(' ').map(area => { const areaData = areasData[area]; if (!areaData) return ''; const colorClass = areaData?.colors?.bg || 'bg-blue-100'; const textColorClass = areaData?.colors?.text || 'text-blue-800'; return `${areaData?.title || area}`; }).filter(link => link).join('') : ''; // Create sub-area links const subAreaLinks = result.topics ? result.topics.split(' ').map(topic => { const primaryArea = result.areas?.split(' ')[0] || 'efficiency'; const areaData = areasData[primaryArea]; if (!areaData || !areaData.subAreas) return ''; const subAreaData = areaData.subAreas[topic]; if (!subAreaData) return ''; const subAreaName = typeof subAreaData === 'string' ? subAreaData : subAreaData?.name || topic; const colorClass = subAreaData?.color || 'bg-gray-100 text-gray-800'; return `${subAreaName}`; }).filter(link => link).join('') : ''; html += `
${result.title}
${score}%
${result.type} ${result.date}
${areaLinks} ${subAreaLinks}
`; }); html += `
`; } // Display resources with collapsible header if (resources.length > 0) { html += `
`; resources.forEach(result => { const score = Math.round(result.score * 100); // Create area links for resources const areaLinks = result.areas ? result.areas.split(' ').map(area => { const areaData = areasData[area]; if (!areaData) return ''; const colorClass = areaData?.colors?.bg || 'bg-green-100'; const textColorClass = areaData?.colors?.text || 'text-green-800'; return `${areaData?.title || area}`; }).filter(link => link).join('') : ''; // Create sub-area links for resources const subAreaLinks = result.topics ? result.topics.split(' ').map(topic => { const primaryArea = result.areas?.split(' ')[0] || 'efficiency'; const areaData = areasData[primaryArea]; if (!areaData || !areaData.subAreas) return ''; const subAreaData = areaData.subAreas[topic]; if (!subAreaData) return ''; const subAreaName = typeof subAreaData === 'string' ? subAreaData : subAreaData?.name || topic; const colorClass = subAreaData?.color || 'bg-gray-100 text-gray-800'; return `${subAreaName}`; }).filter(link => link).join('') : ''; html += `
${result.title}
${score}%
${result.type} ${result.date}
${areaLinks} ${subAreaLinks}
`; }); html += `
`; } document.getElementById('search-results').innerHTML = html; } // Add this function to handle category toggling window.toggleCategory = function(category) { const content = document.getElementById(`${category}-content`); const arrow = document.getElementById(`${category}-arrow`); if (content.style.display === 'none') { content.style.display = 'block'; arrow.style.transform = 'rotate(0deg)'; } else { content.style.display = 'none'; arrow.style.transform = 'rotate(-90deg)'; } };