import Fuse from 'fuse.js'; import type { Project, FilterState, Network } from '../types/project'; export function filterAndSortProjects( projects: Project[], filters: FilterState ): Project[] { let filtered = projects.filter(p => p.network === filters.network); if (filters.tags.length > 0) { filtered = filtered.filter(project => filters.tags.every(tag => project.tags.includes(tag)) ); } if (filters.query) { const fuse = new Fuse(filtered, { keys: [ { name: 'name', weight: 2 }, { name: 'description', weight: 1 }, { name: 'tags', weight: 1 }, { name: 'owner', weight: 0.5 }, { name: 'domain', weight: 0.5 }, { name: 'type', weight: 0.5 } ], threshold: 0.3, includeScore: true }); const searchResults = fuse.search(filters.query); filtered = searchResults.map(result => result.item); } switch (filters.sort) { case 'stars': return [...filtered].sort((a, b) => (b.stars || 0) - (a.stars || 0)); case 'alphabetical': return [...filtered].sort((a, b) => a.name.localeCompare(b.name)); default: return filtered; } } export function getTagsByNetwork(projects: Project[]): Record { const tagsByNetwork: Record = { atproto: [], activitypub: [] }; // Collect all unique tags for each network projects.forEach(project => { project.tags.forEach(tag => { if (!tagsByNetwork[project.network].includes(tag)) { tagsByNetwork[project.network].push(tag); } }); }); // Sort tags alphabetically for each network Object.keys(tagsByNetwork).forEach(network => { tagsByNetwork[network as Network].sort(); }); return tagsByNetwork; }