tahamajs/RR / Docs /visualizer /src /ui /module_catalog.js
tahamajs's picture
download
raw
6.7 kB
/**
* ui/module_catalog.js
* ====================
* Research Repository Modal & Module Catalog Browser (240+ Modules).
*/
import { escapeHtml } from '../utils/dom.js';
let catalogModules = [];
let activeCategory = 'all';
let activeSort = 'accuracy';
let activeSearchQuery = '';
/**
* Initializes the module library modal and populates cards.
* @param {Array<object>} modules - Module catalog array
* @param {Function} onSelectModule - Callback when a module card is picked
*/
export function initModuleCatalog(modules, onSelectModule) {
catalogModules = modules || [];
const modal = document.getElementById('module-modal');
const openBtn = document.getElementById('btn-open-catalog');
const closeBtn = document.getElementById('btn-close-modal');
const searchInput = document.getElementById('modal-search-input');
const countEl = document.getElementById('modal-module-count');
if (countEl) countEl.innerText = catalogModules.length;
if (openBtn && modal) {
openBtn.addEventListener('click', () => {
modal.classList.remove('hidden');
renderModuleCards(onSelectModule);
});
}
if (closeBtn && modal) {
closeBtn.addEventListener('click', () => {
modal.classList.add('hidden');
});
}
if (searchInput) {
searchInput.addEventListener('input', (e) => {
activeSearchQuery = e.target.value.trim().toLowerCase();
renderModuleCards(onSelectModule);
});
}
// Category pills
document.querySelectorAll('.cat-pill').forEach(pill => {
pill.addEventListener('click', () => {
document.querySelectorAll('.cat-pill').forEach(p => p.classList.remove('active'));
pill.classList.add('active');
activeCategory = pill.dataset.cat;
renderModuleCards(onSelectModule);
});
});
// Sort buttons
document.querySelectorAll('.sort-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.sort-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
activeSort = btn.dataset.sort;
renderModuleCards(onSelectModule);
});
});
// Quick Select Dropdown synchronization
const quickSelect = document.getElementById('quick-module-select');
if (quickSelect) {
quickSelect.innerHTML = '<option value="" disabled selected>⚡ Quick Pick (241 Modules)...</option>';
catalogModules.forEach(m => {
const opt = document.createElement('option');
opt.value = m.id;
opt.textContent = `${m.icon || '⚡'} ${m.name || m.id}`;
quickSelect.appendChild(opt);
});
quickSelect.addEventListener('change', (e) => {
const chosen = catalogModules.find(m => m.id === e.target.value);
if (chosen && onSelectModule) onSelectModule(chosen);
});
}
}
/**
* Renders filtered and sorted module cards into the gallery grid.
* @param {Function} onSelectModule - Callback when a card is selected
*/
export function renderModuleCards(onSelectModule) {
const grid = document.getElementById('modal-module-grid');
if (!grid) return;
let filtered = catalogModules.filter(m => {
if (activeCategory !== 'all' && m.category !== activeCategory) return false;
if (activeSearchQuery) {
const haystack = `${m.name} ${m.id} ${m.category} ${m.description || ''} ${m.file || ''}`.toLowerCase();
if (!haystack.includes(activeSearchQuery)) return false;
}
return true;
});
// Sorting
filtered.sort((a, b) => {
if (activeSort === 'accuracy') {
const accA = (a.verified_benchmark && a.verified_benchmark.accuracy_pct) || 0;
const accB = (b.verified_benchmark && b.verified_benchmark.accuracy_pct) || 0;
return accB - accA;
} else if (activeSort === 'savings') {
const rA = (a.model_projections && a.model_projections.distilbert && a.model_projections.distilbert.savings_ratio) || 1.0;
const rB = (b.model_projections && b.model_projections.distilbert && b.model_projections.distilbert.savings_ratio) || 1.0;
return rB - rA;
} else if (activeSort === 'name') {
return (a.name || a.id).localeCompare(b.name || b.id);
}
return (a.category || '').localeCompare(b.category || '');
});
grid.innerHTML = filtered.map(m => {
const bench = m.verified_benchmark || {};
const isPass = bench.status === 'PASS';
return `
<div class="modal-card" data-module-id="${m.id}">
<div class="modal-card-head">
<span class="mc-icon">${m.icon || '⚡'}</span>
<strong>${escapeHtml(m.name || m.id)}</strong>
<span class="badge ${isPass ? 'badge-pass' : 'badge-neutral'}">${bench.status || 'VERIFIED'}</span>
</div>
<p class="mc-desc">${escapeHtml(m.description || '')}</p>
<div class="mc-footer">
<span class="mc-cat">${escapeHtml(m.category || '')}</span>
<div style="display:flex;gap:6px;">
<button class="round-button btn-view-doc" data-module-id="${m.id}" style="padding:4px 8px;font-size:10px;background:rgba(56,189,248,0.15);color:#38bdf8;border:1px solid rgba(56,189,248,0.4);">📖 Doc</button>
<button class="round-button btn-apply" data-module-id="${m.id}" style="padding:4px 8px;font-size:10px;">Apply</button>
</div>
</div>
</div>
`;
}).join('');
// Bind card click triggers & Doc reader triggers
grid.querySelectorAll('.btn-view-doc').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const modId = btn.dataset.moduleId;
const target = catalogModules.find(m => m.id === modId);
if (target && window.openModuleDoc) {
window.openModuleDoc(target);
}
});
});
grid.querySelectorAll('.modal-card').forEach(card => {
card.addEventListener('click', (e) => {
const modId = card.dataset.moduleId;
const target = catalogModules.find(m => m.id === modId);
if (target && onSelectModule) {
onSelectModule(target);
const modal = document.getElementById('module-modal');
if (modal) modal.classList.add('hidden');
}
});
});
}

Xet Storage Details

Size:
6.7 kB
·
Xet hash:
36d9003a3fb30617495433621114beb7c24b93f6742a19a8359573cfd2275f4e

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.