Skip to content

Instantly share code, notes, and snippets.

@evanwill
Last active May 16, 2023 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evanwill/abe532493a9a90b9a3db5172823e86f2 to your computer and use it in GitHub Desktop.
Save evanwill/abe532493a9a90b9a3db5172823e86f2 to your computer and use it in GitHub Desktop.
CollectionBuilder-GH javascript-based Timeline layout replacement

CollectionBuilder-GH javascript-based Timeline layout replacement

If you need to sort BC dates or dates < 1000 AD, using the built in Liquid sorting doesn't work. This example implements a JS based version of the Timeline instead.

  1. From your metadata's "date" field create a new column "year" that is only the year, all values must be a number. For BC dates, the year should be a negative number.
  2. In your template replace "_layouts/timeline.html" and "_includes/js/timeline-js.html" with the version in this gist.

If you want to use TimelineJS feature, you will also want to edit the "assets/data/timelinejs.json" to use item.year rather than parsing the date.

{%- if site.data.theme.icons -%}{% assign icons = site.data.theme.icons %}{% else %}
{% assign cb_icons = site.pages | where: "name","cb-icons.svg" | first %}
{% assign icons = cb_icons.icons %}{%- endif -%}
{%- assign items = site.data[site.metadata] | where_exp: 'item','item.year' -%}
<script>
function makeCard(obj) {
// find images and link
// find item link
var itemHref = `{{ '/item.html' | relative_url }}?id=${obj.objectid}`;
// find images
var thumbSrc;
// add images or thumb for objects based on format
if(obj.youtubeid) {
thumbSrc = 'https://img.youtube.com/vi/' + obj.youtubeid + '/hqdefault.jpg';
} else if (obj.format.includes("image")) {
if(obj.filename.includes("/")) {
thumbSrc = obj.filename;
} else {
thumbSrc = "{{ '/objects/' | relative_url }}" + obj.filename;
}
} else if (obj.format.includes("audio")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-audio }}.svg';
} else if (obj.format.includes("video")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-video }}.svg';
} else if (obj.format.includes("pdf")) {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-pdf }}.svg';
} else {
thumbSrc = '{{ "/assets/lib/icons/" | relative_url }}{{ icons.icon-default }}.svg';
}
// create card based on type
if (obj.youtubeid || obj.format.includes("image")){
var card = `<div class="col-lg-4 col-md-6">
<a href="${itemHref}">
<img class="lazyload img-thumbnail" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3C/svg%3E" data-src="${thumbSrc}" alt="${obj.title}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="${obj.title} | ${obj.date}">
</a>
</div>`;
}
else {
var card = `<div class="col-lg-4 col-md-6">
<a href="${itemHref}">
<div class="card">
<div class="card-body text-center">
<h4 class="card-title text-dark">${obj.title}</h4>
<img class="lazyload w-50" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3C/svg%3E" data-src="${thumbSrc}" alt="filetype thumbnail">
</div>
</div>
</a>
</div>`;
}
return card;
}
function pageInit(items) {
// get dates from metadata and clean to years
clean_years = [];
for (var i = 0; i < items.length; i++) {
if (typeof items[i].date === "number") { clean_years.push(items[i].date); }
}
// find unique years
unique_years = clean_years.filter(function(value, index, self) { return self.indexOf(value) === index; }).sort((a, b) => a - b);
document.getElementById("yearRange").innerHTML = `<a href="#y${ unique_years[0] }">${ unique_years[0] < 0 ? unique_years[0]*-1 + ' BC' : unique_years[0] }</a> to <a href="#y${ unique_years[unique_years.length - 1] }">${ unique_years[unique_years.length - 1] < 0 ? unique_years[unique_years.length - 1]*-1 + ' BC' : unique_years[unique_years.length - 1] }</a>`;
// figure out navYears
var dropYears = "";
{%- if site.data.theme.year-navigation -%}
var navYears = {{ site.data.theme.year-navigation | split: ";" | jsonify }};
{%- else -%}
const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
if (unique_years.length < 20){
var navYears = everyNth(unique_years, 2);
}
else {
var navYears = everyNth(unique_years, 5);
}
{% endif %}
for (var i = 0; i < navYears.length; i++){
dropYears += `<a class="dropdown-item" href="#y${ navYears[i] }">${ navYears[i] < 0 ? navYears[i]*-1 + ' BC' : navYears[i] }</a>`;
}
// add nav years dropdown
document.getElementById("navDropYears").innerHTML = dropYears;
// add navYears to page
var yearTable = "";
// iterate over unique years
for (var i = 0; i < unique_years.length; i++) {
var years = "";
// find items for the year
var yearItems = items.filter(item => item.date == unique_years[i]);
// create cards for each
var yearItemCards = "";
yearItems.forEach((item) => { yearItemCards += makeCard(item); });
// create table row for year
var yearRow = `<tr id="y${unique_years[i]}"><th><h3>${ unique_years[i] < 0 ? unique_years[i]*-1 + ' BC' : unique_years[i] }</h3></th><td><div class="row">${yearItemCards}</div></td></tr>`;
// add to var
yearTable += yearRow;
}
document.getElementById("timelineBody").innerHTML = yearTable;
// init bootstrap tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
// highlight year if hash
if(window.location.hash) {
var hashfilter = decodeURIComponent(location.hash.substr(1));
document.querySelector("tr#" + hashfilter).classList.add("bg-info");
}
}
/* add items */
var items = [
{% for i in items %}
{ "title":{{ i.title | strip | jsonify }}, "date": {{ i.year | times: 1 }}, "format":{% if i.format %}{{ i.format | jsonify }}{% else %}""{% endif %}, {% if i.youtubeid %} "youtube": {{ i.youtubeid | jsonify }}, {% endif %}{% if i.filename contains '/' %}"filename": "{{ i.filename }}" {% else %}"filename":"{{ '/objects/' | relative_url | append: i.filename }}"{% endif %}, "objectid":{{ i.objectid | jsonify }} }{% unless forloop.last %},{% endunless %}{% endfor %}
];
/* init timeline */
pageInit(items);
</script>
---
# "Timeline" page
layout: page
custom-foot: js/timeline-js.html
---
<div class="dropdown float-end" id="year-nav">
<button class="btn btn-primary dropdown-toggle" type="button" id="yearButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Year
</button>
<div class="dropdown-menu" aria-labelledby="yearButton" id="navDropYears">
</div>
</div>
{{ content }}
<h3 id="yearRange"></h3>
<table id="timeline" class="table table-striped">
<tbody id="timelineBody">
</tbody>
</table>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment