Files
Personal-Website/client/js/filter.js
T

46 lines
1.7 KiB
JavaScript

// 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 = '';
});
});
}