Spaces:
Running
Running
File size: 6,571 Bytes
1e32f6a d635592 1e32f6a d635592 1e32f6a d635592 1e32f6a d635592 1e32f6a d635592 1e32f6a 609c06b 3409b6b 0c51417 1e32f6a d635592 1e32f6a d635592 1e32f6a fd5d5af 1e32f6a fd5d5af 1e32f6a fd5d5af 1e32f6a d635592 1e32f6a d635592 1e32f6a ea0ddf6 1e32f6a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
const statusDiv = document.getElementById('status');
const searchInput = document.getElementById('search-input');
const resultsDiv = document.getElementById('results');
const searchButton = document.getElementById('search-button');
const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress-bar');
const dataInfoDiv = document.getElementById('data-info');
const deleteDataButton = document.getElementById('delete-data-button');
const deleteButtonContainer = document.getElementById('delete-button-container');
const worker = new Worker('worker.js', { type: 'module' });
deleteButtonContainer.classList.add('hidden');
// Initial state
// searchInput.disabled = true; // Removed to enable during initialization
// searchButton.disabled = true; // Removed to enable during initialization
// Ensure delete button is always visible (UI-level control). Worker will decide if data exists.
deleteButtonContainer.classList.remove('hidden');
// Helper to format bytes to MB
function formatBytesToMB(bytes) {
return (bytes / (1024 * 1024)).toFixed(2);
}
worker.onmessage = (event) => {
const { type, payload } = event.data;
if (type === 'loading') {
statusDiv.textContent = payload;
progressContainer.classList.remove('hidden');
} else if (type === 'progress') {
const progressPercentage = Math.round(payload.progress);
progressBar.style.width = `${progressPercentage || 0}%`;
statusDiv.textContent = payload.detail;
progressContainer.classList.remove('hidden');
} else if (type === 'ready') {
statusDiv.textContent = ''; // Clear status when index is ready
progressContainer.classList.add('hidden');
searchInput.disabled = false;
searchButton.disabled = false;
// Delete button remains visible at all times per UI requirement
} else if (type === 'results') {
// statusDiv.textContent = 'Search complete.'; // Removed as results themselves convey completion
progressContainer.classList.add('hidden'); // Hide progress bar
renderResults(payload);
statusDiv.textContent = ''; // Clear status after search is complete
deleteButtonContainer.classList.remove('hidden'); // Ensure delete button is visible
} else if (type === 'indexSize') {
// Keep delete button visible always. Worker tells us whether data is cached.
// Visual enable/disable could be added later if desired.
if (payload.indexCached) {
dataInfoDiv.textContent = ''; // Clear data info if cached
searchInput.disabled = false;
searchButton.disabled = false;
if (payload.modelCached) {
statusDiv.textContent = ''; // Clear status if both index and model are loaded
} else {
statusDiv.textContent = ''; // Clear status if index is loaded, model will load on first search
}
} else {
dataInfoDiv.textContent = ''; // Clear data info if not cached
// Keep delete button visible even if no cached data
searchInput.disabled = false; // Ensure input is enabled
searchButton.disabled = false; // Ensure button is enabled
// Render message with an inline info icon that has an accessible tooltip
const sizeMB = formatBytesToMB(payload.size);
// Friendly, non-scary message with accessible tooltip
statusDiv.innerHTML = `Heads‑up: one‑time download <strong>~${Math.round(sizeMB)} MB</strong> to enable fast, private searches in your browser. Runs locally — delete anytime.`;
}
} else if (type === 'dataDeleted') {
// Show confirmation message briefly and then reload the page so the UI and worker state fully reset
statusDiv.textContent = payload;
dataInfoDiv.textContent = ''; // Clear data info
progressContainer.classList.add('hidden'); // Hide progress bar
// Give the user a moment to see the confirmation, then reload to clear caches and restart the worker
setTimeout(() => {
// A hard reload ensures service worker/worker gets a clean start in some environments
try {
location.reload();
} catch (e) {
// If reload fails for any reason, fall back to re-requesting index size
worker.postMessage({ type: 'getIndexSize' });
}
}, 700);
} else if (type === 'error') {
statusDiv.textContent = `Error: ${payload}`;
progressContainer.classList.add('hidden');
}
};
// Send initial request for index size when the page loads
worker.postMessage({ type: 'getIndexSize' });
function doSearch() {
const query = searchInput.value;
if (query) {
worker.postMessage({ type: 'search', payload: query });
statusDiv.textContent = 'Searching...';
resultsDiv.innerHTML = ''; // Clear previous results
return true;
} else {
resultsDiv.innerHTML = '<p class="text-gray-500">Please enter a query.</p>';
return false;
}
}
searchButton.addEventListener('click', doSearch);
// Trigger search on Enter (without Shift). Shift+Enter inserts newline.
searchInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
// Prevent newline from being inserted
e.preventDefault();
doSearch();
}
});
// Make confirm non-blocking so the click handler returns quickly (avoids long task warnings)
deleteDataButton.addEventListener('click', () => {
setTimeout(() => {
if (confirm('Are you sure you want to delete the cached data?')) {
worker.postMessage({ type: 'deleteData' });
}
}, 0);
});
function renderResults(results) {
resultsDiv.innerHTML = '';
if (results.length === 0) {
resultsDiv.innerHTML = '<p class="text-gray-500">No results found.</p>';
return;
}
results.forEach(result => {
const card = document.createElement('div');
card.className = 'bg-gray-50 p-4 rounded-lg shadow mb-4';
// Handle null author gracefully; categories were removed from the index
const authorText = result.author ? `- ${result.author}` : '- Unknown Author';
card.innerHTML = `
<p class="text-lg font-medium text-gray-800">"${result.quote}"</p>
<p class="text-right text-gray-600 italic mt-2">${authorText}</p>
`;
resultsDiv.appendChild(card);
});
} |