Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add filters, remove times and dates (#29)
* feat: add filters (WIP) * tweaks to card sizes on mobile * fix: mobile css for filters * feat: remove schedule Co-authored-by: Nealevf <neale@rogueamoeba.com>
- Loading branch information
1 parent
bdd67ce
commit 83418eb
Showing
7 changed files
with
119 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<div class="card card--filters"> | ||
<h2>Filter Streams</h2> | ||
<p> | ||
<label for="subject">Filter by Subject:</label> | ||
<select id="subject" name="subject"> | ||
<option value="" selected>--</option> | ||
{% for value in streams.subjects %} | ||
<option value="{{ value }}">{{ value }}</option> | ||
{% endfor %} | ||
</select> | ||
</p> | ||
<p> | ||
<label for="ages">Filter by Age:</label> | ||
<select id="ages" name="ages"> | ||
<option value="" selected>--</option> | ||
{% for value in streams.ageRanges %} | ||
<option value="{{ value }}">{{ value }}</option> | ||
{% endfor %} | ||
</select> | ||
</p> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<article class="card card--stream" data-status data-subject="{{ item.subject }}" data-ages="{{ item.ageRange }}"> | ||
<div class="card-image"> | ||
<img src="{{ item.photo[0].url }}" alt="" loading="lazy" /> | ||
</div> | ||
<h2><a rel="external noopener noreferrer" href="{{ item.link }}" target="_blank">{{ item.name }}<span class="sr-only"> (opens in new window)</span></a></h2> | ||
<p>By <a rel="external noopener noreferrer" href="{{ item.creatorLink }}">{{ item.creatorName }}</a>{% if item.platform !== 'Web' %} on {{ item.platform }}{% endif %}</p> | ||
<div class="meta"> | ||
<span class="subject">{{ item.subject }}</span> | ||
</div> | ||
<div class="badge"> | ||
<span class="label">Done</span> | ||
<svg viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg"> | ||
<g fill="currentColor"> | ||
<path d="M0,0 L60,0 C71.045695,0 80,8.954305 80,20 L80,80 L80,80 L0,0 Z"></path> | ||
</g> | ||
</svg> | ||
</div> | ||
</article> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,129 +1,32 @@ | ||
import { format, isPast, isAfter, isBefore, isToday, isTomorrow, addHours, addDays, endOfTomorrow } from "/web_modules/date-fns.js"; | ||
|
||
function insertHeading(stream, label) { | ||
const heading = document.createElement('h2'); | ||
heading.className = 'clearfix date-title'; | ||
heading.textContent = label; | ||
stream.parentNode.insertBefore(heading, stream); | ||
} | ||
|
||
function formatDates(streams) { | ||
streams.forEach(function(stream) { | ||
const date = stream.querySelector('.card-date'); | ||
const startTime = date.getAttribute('datetime'); | ||
date.innerText = `${format(new Date(startTime), 'PP')} at ${format(new Date(startTime), 'p')}`; | ||
}); | ||
} | ||
|
||
function groupStreams(streams) { | ||
let offset = false; | ||
streams.forEach(function(stream) { | ||
const startTime = stream.querySelector('.card-date').getAttribute('datetime'); | ||
// Stream is today. | ||
if (isToday(new Date(startTime))) { | ||
if (!offset) { | ||
insertHeading(stream, 'Today’s Livestreams'); | ||
offset = '0'; | ||
} | ||
} | ||
|
||
// Stream is tomorrow. | ||
if (isTomorrow(new Date(startTime))) { | ||
if (!offset || offset === '0') { | ||
insertHeading(stream, 'Tomorrow’s Livestreams'); | ||
offset = '1'; | ||
} | ||
} | ||
|
||
// Stream is in two days. | ||
if (isAfter(new Date(startTime), endOfTomorrow()) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 1))) { | ||
if (offset === '1') { | ||
insertHeading(stream, `${format(new Date(startTime), 'EEEE')}’s Livestreams`); | ||
offset = '2'; | ||
} | ||
} | ||
// Stream is in three days. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 1)) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 2))) { | ||
if (offset === '2') { | ||
insertHeading(stream, `${format(new Date(startTime), 'EEEE')}’s Livestreams`); | ||
offset = '3'; | ||
} | ||
} | ||
// Stream is in four days. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 2)) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 3))) { | ||
if (offset === '3') { | ||
insertHeading(stream, `${format(new Date(startTime), 'EEEE')}’s Livestreams`); | ||
offset = '4'; | ||
} | ||
} | ||
// Stream is in five days. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 3)) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 4))) { | ||
if (offset === '4') { | ||
insertHeading(stream, `${format(new Date(startTime), 'EEEE')}’s Livestreams`); | ||
offset = '5'; | ||
} | ||
} | ||
// Stream is in six days. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 4)) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 5))) { | ||
if (offset === '5') { | ||
insertHeading(stream, `${format(new Date(startTime), 'EEEE')}’s Livestreams`); | ||
offset = '6'; | ||
} | ||
} | ||
// Stream is next week. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 5)) && isBefore(new Date(startTime), addDays(endOfTomorrow(), 13))) { | ||
if (offset === '6') { | ||
insertHeading(stream, 'Next Week’s Livestreams'); | ||
offset = 'nextweek'; | ||
} | ||
} | ||
// Stream is later. | ||
if (isAfter(new Date(startTime), addDays(endOfTomorrow(), 13))) { | ||
if (offset === 'nextweek') { | ||
insertHeading(stream, 'Future Livestreams'); | ||
offset = 'later'; | ||
} | ||
function filterStreams() { | ||
const streams = document.querySelectorAll('article.card'); | ||
const ageRange = document.getElementById('ages').value !== '' ? document.getElementById('ages').value : false; | ||
const subject = document.getElementById('subject').value !== '' ? document.getElementById('subject').value : false; | ||
|
||
const matchedStreams = [...streams].filter(stream => { | ||
if (ageRange && subject) { | ||
return stream.dataset.ages === ageRange && stream.dataset.subject === subject; | ||
} else if (ageRange) { | ||
return stream.dataset.ages === ageRange; | ||
} else if (subject) { | ||
return stream.dataset.subject === subject; | ||
} else { | ||
return stream; | ||
} | ||
}); | ||
} | ||
|
||
function updateStreams() { | ||
const streams = document.querySelectorAll('article.card'); | ||
|
||
streams.forEach(function(stream) { | ||
const date = stream.querySelector('.card-date'); | ||
const startTime = date.getAttribute('datetime'); | ||
const endTime = date.dataset.end; | ||
|
||
// Stream end time is in the past. | ||
if (isPast(new Date(endTime))) { | ||
stream.dataset.status = 'done'; | ||
stream.querySelector('.badge .label').innerText = 'done'; | ||
} | ||
// Stream start time is within the next hour. | ||
if (isAfter(new Date(startTime), new Date()) && isBefore(new Date(startTime), addHours(new Date(), 1))) { | ||
stream.dataset.status = 'soon'; | ||
stream.querySelector('.badge .label').innerText = 'soon'; | ||
} | ||
// Stream is live. | ||
if (isAfter(new Date(), new Date(startTime)) && isBefore(new Date(), new Date(endTime))) { | ||
stream.dataset.status = 'live'; | ||
stream.querySelector('.badge .label').innerText = 'live'; | ||
streams.forEach((stream) => { | ||
if (!matchedStreams.includes(stream)) { | ||
stream.setAttribute('hidden', ''); | ||
} else { | ||
stream.removeAttribute('hidden'); | ||
} | ||
}); | ||
} | ||
|
||
function timedUpdate() { | ||
updateStreams(); | ||
setTimeout(timedUpdate, 60000); | ||
} | ||
|
||
const streams = document.querySelectorAll('article.card'); | ||
|
||
if (streams.length > 0) { | ||
formatDates(streams); | ||
groupStreams(streams); | ||
timedUpdate(); | ||
} | ||
document.addEventListener('input', function (event) { | ||
if (event.target.id !== 'ages' && event.target.id !=='subject') return; | ||
|
||
filterStreams(); | ||
}, false); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters