/** * Collections page functionality */ import { createChoices, getChoicesValues, type Choices } from '../choices'; import { FuzzySearch, SearchItem } from '../search'; import { fetchData, debounce, escapeHtml, getGitHubUrl } from '../utils'; import { setupModal, openFileModal } from '../modal'; interface Collection extends SearchItem { id: string; name: string; path: string; tags?: string[]; featured?: boolean; itemCount: number; } interface CollectionsData { items: Collection[]; filters: { tags: string[]; }; } const resourceType = 'collection'; let allItems: Collection[] = []; let search = new FuzzySearch(); let tagSelect: Choices; let currentFilters = { tags: [] as string[], featured: false }; function applyFiltersAndRender(): void { const searchInput = document.getElementById('search-input') as HTMLInputElement; const countEl = document.getElementById('results-count'); const query = searchInput?.value || ''; let results = query ? search.search(query) : [...allItems]; if (currentFilters.tags.length > 0) { results = results.filter(item => item.tags?.some(tag => currentFilters.tags.includes(tag))); } if (currentFilters.featured) { results = results.filter(item => item.featured); } renderItems(results, query); const activeFilters: string[] = []; if (currentFilters.tags.length > 0) activeFilters.push(`${currentFilters.tags.length} tag${currentFilters.tags.length > 1 ? 's' : ''}`); if (currentFilters.featured) activeFilters.push('featured'); let countText = `${results.length} of ${allItems.length} collections`; if (activeFilters.length > 0) { countText += ` (filtered by ${activeFilters.join(', ')})`; } if (countEl) countEl.textContent = countText; } function renderItems(items: Collection[], query = ''): void { const list = document.getElementById('resource-list'); if (!list) return; if (items.length === 0) { list.innerHTML = '

No collections found

Try a different search term or adjust filters

'; return; } list.innerHTML = items.map(item => `
${item.featured ? '⭐ ' : ''}${query ? search.highlight(item.name, query) : escapeHtml(item.name)}
${escapeHtml(item.description || 'No description')}
${item.itemCount} items ${item.tags?.slice(0, 4).map(t => `${escapeHtml(t)}`).join('') || ''} ${item.tags && item.tags.length > 4 ? `+${item.tags.length - 4} more` : ''}
`).join(''); // Add click handlers list.querySelectorAll('.resource-item').forEach(el => { el.addEventListener('click', () => { const path = (el as HTMLElement).dataset.path; if (path) openFileModal(path, resourceType); }); }); } export async function initCollectionsPage(): Promise { const list = document.getElementById('resource-list'); const searchInput = document.getElementById('search-input') as HTMLInputElement; const featuredCheckbox = document.getElementById('filter-featured') as HTMLInputElement; const clearFiltersBtn = document.getElementById('clear-filters'); const data = await fetchData('collections.json'); if (!data || !data.items) { if (list) list.innerHTML = '

Failed to load data

'; return; } allItems = data.items; // Map collection items to search items const searchItems = allItems.map(item => ({ ...item, title: item.name, searchText: `${item.name} ${item.description} ${item.tags?.join(' ') || ''}`.toLowerCase() })); search.setItems(searchItems); tagSelect = createChoices('#filter-tag', { placeholderValue: 'All Tags' }); tagSelect.setChoices(data.filters.tags.map(t => ({ value: t, label: t })), 'value', 'label', true); document.getElementById('filter-tag')?.addEventListener('change', () => { currentFilters.tags = getChoicesValues(tagSelect); applyFiltersAndRender(); }); applyFiltersAndRender(); searchInput?.addEventListener('input', debounce(() => applyFiltersAndRender(), 200)); featuredCheckbox?.addEventListener('change', () => { currentFilters.featured = featuredCheckbox.checked; applyFiltersAndRender(); }); clearFiltersBtn?.addEventListener('click', () => { currentFilters = { tags: [], featured: false }; tagSelect.removeActiveItems(); if (featuredCheckbox) featuredCheckbox.checked = false; if (searchInput) searchInput.value = ''; applyFiltersAndRender(); }); setupModal(); } // Auto-initialize when DOM is ready document.addEventListener('DOMContentLoaded', initCollectionsPage);