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})();