import { AFS } from './afs.modern.js'; import games from '../data/games.json' with {type: 'json'}; // Basic variable replacements const numJoined = 0; // SEE HERE FOR DATE FORMAT INFO: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format const startDate = '2026-02-01T00:00:00'; const endDate = '2026-02-28T23:59:59'; // Date formatting stuff. You probably only need to touch locale and time zone. const locale = 'en-US'; const timeZone = 'America/Chicago'; const dateOptions = { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: timeZone }; // DON'T EDIT BELOW THIS LINE // unless you know what you're doing. const start = new Date(startDate); const end = new Date(endDate); const startDateElt = document.getElementById('startDate'); const endDateElt = document.getElementById('endDate'); const dateElt = document.getElementById('dates'); const joinedElt = document.getElementById('joinedCount'); const entriesElt = document.getElementById('entriesCount'); const daysElt = document.getElementById('days'); const hoursElt = document.getElementById('hours'); const minutesElt = document.getElementById('minutes'); const secondsElt = document.getElementById('seconds'); const startString = start.toLocaleString(locale, dateOptions); const endString = end.toLocaleString(locale, dateOptions); const list = document.getElementById('list'); const allTags = games.map(g => g.tags).reduce((g1, g2) => { return g1.concat(g2); }).filter((t, i, arr) => { return arr.indexOf(t) === i }).sort(); const dayMult = 24*60*60; const hourMult = 60*60; const minuteMult = 60; if (joinedElt) joinedElt.textContent = numJoined; if (entriesElt) entriesElt.textContent = games.length; if (startDateElt) startDateElt.textContent = startString; if (endDateElt) endDateElt.textContent = endString; const countdownTick = () => { const now = Date.now(); let diff; if (now < start.getTime()) { // Jam hasn't started yet diff = (start.getTime() - now) / 1000; // get total # of seconds } else if (now < end.getTime()) { // Jam has started but not ended diff = (end.getTime() - now) / 1000; } else { // Jam has ended dates.innerHTML = `The jam is now over. It ran from ${startString} to ${endString}. View ${numEntries} ${numEntries !== 1 ? 'entries' : 'entry'}` } if (diff) { const days = Math.floor(diff / dayMult); diff = diff - (days * dayMult); const hours = Math.floor(diff / hourMult); diff = diff - (hours * hourMult); const minutes = Math.floor(diff / minuteMult); diff = diff - (minutes * minuteMult); const seconds = Math.floor(diff); daysElt.textContent = days; hoursElt.textContent = hours; minutesElt.textContent = minutes; secondsElt.textContent = seconds; } } if (document.querySelector('.clock')) { countdownTick(); setInterval(() => { countdownTick(); }, 1000); } if (list) { list.innerHTML = games.map((item, i) => { return `
'platforms:'+p).join(" ")}" data-title="${item.title}" data-date="${item.submitTime}">
${item.title} thumbnail image

${item.title}

${item.authors.map((auth) => { return `${auth.name}`; }).join(", ")}
${item.blurb}
`; }).join(""); const tagsElt = document.getElementById('tags'); tagsElt.innerHTML = ``+allTags.map((t) => { return `` }).join(""); const afs = new AFS({ // Required Selectors containerSelector: '#list', itemSelector: '.item', // CSS Classes activeClass: 'active', hiddenClass: 'hidden', transitionClass: 'afs-transition', searchKeys: ['title', 'authors', 'tags'], debounceTime: 200, // search input delay // Date Handling dateFormat: 'YYYY-MM-DD', dateFilter: { enabled: true, format: 'YYYY-MM-DDThh:mm:ss' }, // Counter Configuration counter: { template: 'Showing {visible} of {total}', showFiltered: true, filteredTemplate: '({filtered} filtered)', noResultsTemplate: 'No items found', formatter: (num) => num.toLocaleString() }, sort: { enabled: true, buttonSelector: '.afs-btn-sort' }, // Animation Configuration animation: { type: 'fade', duration: 200, easing: 'ease-out', inClass: 'afs-animation-enter', outClass: 'afs-animation-leave' }, // Lifecycle Options responsive: true, preserveState: false, stateExpiry: 86400000, // 24 hours observeDOM: false, // Style Configuration styles: { colors: { primary: '#000', background: '#e5e7eb', text: '#000', textHover: '#fff' } } }); // add date range filter afs.dateFilter.addDateRange({ key: 'date', container: document.querySelector('#date-filter'), format: 'YYYY-MM-DD', minDate: new Date(startDate.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)[0]), maxDate: new Date(endDate.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)[0]) }); // fixes some behavior of the sort buttons document.querySelectorAll('button.custom-sort:not([data-sort-key="shuffle"])').forEach((elt) => { elt.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const btn = e.target.closest('button'); document.querySelectorAll('button.custom-sort:not([data-sort-key="'+btn.getAttribute('data-sort-key')+'"])').forEach((s) => { s.classList.remove('sort-active'); }); if (btn.classList.contains('sort-active')) { if (btn.getAttribute('data-sort-direction') === 'asc') { btn.setAttribute('data-sort-direction', 'desc'); btn.querySelector('img').src = './images/sort-desc.svg'; } else { btn.setAttribute('data-sort-direction', 'asc'); btn.querySelector('img').src = './images/sort-asc.svg'; } afs.sort.sort(btn.getAttribute('data-sort-key'), btn.getAttribute('data-sort-direction')); } else { btn.classList.add('sort-active'); afs.sort.sort(btn.getAttribute('data-sort-key'), btn.getAttribute('data-sort-direction')); } }); }); // random sort button document.querySelector('[data-sort-key="shuffle"]').addEventListener('click', (e) => { afs.sort.shuffle(); }); }