| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- /* Public site behavior: hiding navigation + gallery lightbox. Vanilla JS. */
- (function () {
- 'use strict';
- /* ---- Navigation: hide on scroll-down, show on scroll-up ------------- */
- var nav = document.getElementById('nav');
- if (nav) {
- var lastY = window.scrollY;
- var onScroll = function () {
- var y = window.scrollY;
- if (y > lastY && y > 80) {
- nav.classList.add('nav-hidden');
- } else if (y < lastY - 2 || y <= 80) {
- nav.classList.remove('nav-hidden');
- }
- lastY = y;
- };
- window.addEventListener('scroll', onScroll, { passive: true });
- }
- /* ---- Topic sections: collapse / expand ------------------------------
- A gallery may be split into topics, each a heading plus its own .grid.
- The button carries the state so the chevron and the panel can both be
- styled from it, and screen readers get it for free. Deliberately not
- remembered anywhere: every visit starts fully expanded. */
- document.addEventListener('click', function (e) {
- var toggle = e.target.closest && e.target.closest('.topic-toggle');
- if (!toggle) return;
- var panel = document.getElementById(toggle.getAttribute('aria-controls'));
- if (!panel) return;
- var open = toggle.getAttribute('aria-expanded') === 'true';
- toggle.setAttribute('aria-expanded', open ? 'false' : 'true');
- panel.hidden = open;
- });
- /* ---- Lightbox for gallery pages -------------------------------------
- Markup contract: every .grid contains <a href="<full-res URL>"><img></a>.
- A gallery with topics has one .grid per section, so they are treated as a
- single sequence in document order — which is the order the client reads
- the page in. */
- var grids = Array.prototype.slice.call(document.querySelectorAll('.grid'));
- if (!grids.length) return;
- var allLinks = [];
- grids.forEach(function (grid) {
- allLinks = allLinks.concat(Array.prototype.slice.call(grid.querySelectorAll('a')));
- });
- if (!allLinks.length) return;
- /* Only what the visitor can actually see right now. Recomputed on open, so
- arrowing through never lands on a photo inside a collapsed topic. */
- var links = allLinks;
- function visibleLinks() {
- return allLinks.filter(function (a) { return a.offsetParent !== null; });
- }
- var box = document.createElement('div');
- box.className = 'lightbox';
- box.innerHTML =
- '<button class="lb-close" aria-label="Close">×</button>' +
- '<button class="lb-prev" aria-label="Previous">‹</button>' +
- '<img alt="">' +
- '<button class="lb-next" aria-label="Next">›</button>' +
- '<span class="lb-count"></span>';
- document.body.appendChild(box);
- var img = box.querySelector('img');
- var count = box.querySelector('.lb-count');
- var current = -1;
- function show(i) {
- current = (i + links.length) % links.length;
- img.src = links[current].href;
- count.textContent = (current + 1) + ' / ' + links.length;
- box.classList.add('open');
- document.body.style.overflow = 'hidden';
- }
- function close() {
- box.classList.remove('open');
- img.src = '';
- document.body.style.overflow = '';
- current = -1;
- }
- allLinks.forEach(function (a) {
- a.addEventListener('click', function (e) {
- e.preventDefault();
- links = visibleLinks();
- var at = links.indexOf(a);
- if (at >= 0) show(at);
- });
- });
- box.querySelector('.lb-close').addEventListener('click', close);
- box.querySelector('.lb-prev').addEventListener('click', function () { show(current - 1); });
- box.querySelector('.lb-next').addEventListener('click', function () { show(current + 1); });
- box.addEventListener('click', function (e) { if (e.target === box) close(); });
- document.addEventListener('keydown', function (e) {
- if (current < 0) return;
- if (e.key === 'Escape') close();
- if (e.key === 'ArrowLeft') show(current - 1);
- if (e.key === 'ArrowRight') show(current + 1);
- });
- /* Basic swipe support */
- var touchX = null;
- box.addEventListener('touchstart', function (e) { touchX = e.touches[0].clientX; }, { passive: true });
- box.addEventListener('touchend', function (e) {
- if (touchX === null || current < 0) return;
- var dx = e.changedTouches[0].clientX - touchX;
- if (dx > 50) show(current - 1);
- else if (dx < -50) show(current + 1);
- touchX = null;
- }, { passive: true });
- })();
|