hmn/src/templates/src/showcase.html

172 lines
4.8 KiB
HTML

{{ template "base.html" . }}
{{ define "extrahead" }}
<script src="{{ static "js/templates.js" }}"></script>
<script src="{{ static "js/showcase.js" }}"></script>
{{ end }}
{{ define "content" }}
<div class="content-block">
<div class="ph2 ph0-ns pb4">
<div class="optionbar">
<div class="tc tl-l w-100 pb2">
<h2 class="di-l mr2-l">Community Showcase</h2>
<ul class="list dib-l">
<li class="dib-ns ma0 ph2">
<a href="{{ .ShowcaseAtomFeedUrl }}"><span class="icon big">4</span> Showcase Feed</a>
</li>
</ul>
</div>
</div>
<div id="showcase-container" class="mh2 mh0-ns pb4"></div>
</div>
</div>
{{ template "showcase_templates.html" }}
<template id="showcase-month">
<h3 data-tmpl="dateHeader" class="mt3 f4 fw5">Unknown Date</h3>
<div data-tmpl="itemsContainer" class="month-container"></div>
</template>
<script>
const ROW_HEIGHT = 300;
const ITEM_SPACING = 4;
const monthTemplate = makeTemplateCloner('showcase-month');
const showcaseItems = JSON.parse("{{ .ShowcaseItems }}");
const addThumbnailFuncs = new Array(showcaseItems.length);
let showcaseContainer = document.querySelector('#showcase-container');
const itemElementsByMonth = []; // array of arrays
let currentMonthElements = [];
let currentMonth = null;
let currentYear = null;
for (let i = 0; i < showcaseItems.length; i++) {
const item = showcaseItems[i];
const date = new Date(item.date * 1000); // TODO(asaf): Verify that this is still correct with our new JSON marshalling
if (date.getMonth() !== currentMonth || date.getFullYear() !== currentYear) {
if (currentMonthElements.length > 0) {
itemElementsByMonth.push(currentMonthElements);
}
currentMonthElements = [];
currentMonth = date.getMonth();
currentYear = date.getFullYear();
}
const [itemEl, addThumbnail] = makeShowcaseItem(item);
itemEl.container.setAttribute('data-index', i);
itemEl.container.setAttribute('data-date', item.date);
addThumbnailFuncs[i] = addThumbnail;
currentMonthElements.push(itemEl.container);
}
if (currentMonthElements.length > 0) {
itemElementsByMonth.push(currentMonthElements);
}
function layout() {
const width = showcaseContainer.getBoundingClientRect().width;
showcaseContainer = emptyElement(showcaseContainer);
function addRow(itemEls, rowWidth, container) {
const totalSpacing = ITEM_SPACING * (itemEls.length - 1);
const scaleFactor = (width / Math.max(rowWidth, width));
const row = document.createElement('div');
row.classList.add('flex');
row.classList.toggle('justify-between', rowWidth >= width);
row.style.marginBottom = `${ITEM_SPACING}px`;
for (const itemEl of itemEls) {
const index = parseInt(itemEl.getAttribute('data-index'), 10);
const item = showcaseItems[index];
const aspect = item.width / item.height;
const baseWidth = (aspect * ROW_HEIGHT) * scaleFactor;
const actualWidth = baseWidth - (totalSpacing / itemEls.length);
itemEl.style.width = `${actualWidth}px`;
itemEl.style.height = `${scaleFactor * ROW_HEIGHT}px`;
itemEl.style.marginRight = `${ITEM_SPACING}px`;
row.appendChild(itemEl);
}
container.appendChild(row);
}
for (const monthEls of itemElementsByMonth) {
const month = monthTemplate();
const firstDate = new Date(parseFloat(monthEls[0].getAttribute('data-date')) * 1000);
month.dateHeader.textContent = firstDate.toLocaleDateString([], { month: 'long', year: 'numeric' });
let rowItemEls = [];
let rowWidth = 0;
for (const itemEl of monthEls) {
const index = parseInt(itemEl.getAttribute('data-index'), 10);
const item = showcaseItems[index];
const aspect = item.width / item.height;
rowWidth += aspect * ROW_HEIGHT;
rowItemEls.push(itemEl);
if (rowWidth > width) {
addRow(rowItemEls, rowWidth, month.itemsContainer);
rowItemEls = [];
rowWidth = 0;
}
}
addRow(rowItemEls, rowWidth, month.itemsContainer);
showcaseContainer.appendChild(month.root);
}
}
function tryLoadImages() {
const OFFSCREEN_THRESHOLD = 0;
const months = document.querySelectorAll('.month-container');
for (const month of months) {
const rect = month.getBoundingClientRect();
const offscreen = (
rect.bottom < -OFFSCREEN_THRESHOLD
|| rect.top > window.innerHeight + OFFSCREEN_THRESHOLD
);
if (!offscreen) {
const items = month.querySelectorAll('.showcase-item');
for (const item of items) {
const i = parseInt(item.getAttribute('data-index'), 10);
addThumbnailFuncs[i]();
}
}
}
}
layout();
layout(); // scrollbars are fun!!
tryLoadImages();
window.addEventListener('resize', () => {
layout();
tryLoadImages();
});
window.addEventListener('scroll', () => {
tryLoadImages();
});
</script>
{{ end }}