internal/web/assets/gallery.js

47 lines · 1835 bytes

 1(() => {
 2  // Justified rows: fill each row to the container width at roughly --row-height.
 3  const layout = (el) => {
 4    const cs = getComputedStyle(el);
 5    const gap = parseFloat(cs.columnGap) || 0;
 6    const target = parseFloat(cs.getPropertyValue('--row-height')) || 320;
 7    const width = el.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
 8    let row = [], sum = 0;
 9    const flush = (last) => {
10      let h = (width - gap * (row.length - 1)) / sum;
11      if (last && h > target) h = target;
12      for (const t of row) {
13        t.style.width = Math.floor(h * t.dataset.ar) + 'px';
14        t.style.height = Math.floor(h) + 'px';
15      }
16      row = [];
17      sum = 0;
18    };
19    for (const t of el.children) {
20      row.push(t);
21      sum += +t.dataset.ar;
22      if ((width - gap * (row.length - 1)) / sum <= target) flush(false);
23    }
24    if (row.length) flush(true);
25  };
26  const layoutAll = () => document.querySelectorAll('.rows').forEach(layout);
27  let timer;
28  addEventListener('resize', () => { clearTimeout(timer); timer = setTimeout(layoutAll, 100); });
29  layoutAll();
30
31  const follow = (sel) => { const a = document.querySelector(sel); if (a) location.href = a.href; };
32  addEventListener('keydown', (e) => {
33    if (e.metaKey || e.ctrlKey || e.altKey || e.shiftKey) return;
34    if (e.key === 'ArrowLeft') follow('a[rel=prev]');
35    else if (e.key === 'ArrowRight') follow('a[rel=next]');
36    else if (e.key === 'Escape') follow('#up');
37  });
38
39  let x0 = null;
40  addEventListener('touchstart', (e) => { x0 = e.touches[0].clientX; }, { passive: true });
41  addEventListener('touchend', (e) => {
42    if (x0 === null) return;
43    const dx = e.changedTouches[0].clientX - x0;
44    x0 = null;
45    if (Math.abs(dx) > 50) follow(dx > 0 ? 'a[rel=prev]' : 'a[rel=next]');
46  }, { passive: true });
47})();