// Portfolio tag filter. The chips are plain links (?tag=...), the server filters too, // so this only makes it instant. export function initFilter(nav) { const list = document.querySelector('[data-filter-list]'); const empty = document.querySelector('[data-filter-empty]'); if (!list) return; const items = [...list.children]; const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)'); function apply(tag) { for (const chip of nav.querySelectorAll('[data-tag]')) { if (chip.dataset.tag === tag) chip.setAttribute('aria-current', 'true'); else chip.removeAttribute('aria-current'); } let shown = 0; for (const item of items) { const match = !tag || item.dataset.tags.split(' ').includes(tag); item.hidden = !match; if (match) { item.classList.add('is-visible'); shown++; } } if (empty) empty.hidden = shown > 0; } nav.addEventListener('click', (event) => { const chip = event.target.closest('[data-tag]'); if (!chip || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; event.preventDefault(); history.replaceState(null, '', chip.href); if (!document.startViewTransition || reducedMotion.matches) { apply(chip.dataset.tag); return; } // names only for the duration of the transition, so they don't clash with page navigation items.forEach((item, index) => (item.style.viewTransitionName = `project-${index}`)); const transition = document.startViewTransition(() => apply(chip.dataset.tag)); transition.finished.finally(() => { for (const item of items) item.style.viewTransitionName = ''; }); }); }