/* global React */ const { useState, useEffect, useMemo, useRef } = React; // Crop masonry columns to the shortest one (desktop only). // JS measures heights after images load and clips taller columns with max-height + overflow:hidden. // Diagnostic logging: open page with ?debug=1 to see per-call measurements in console. function useEvenColumns(ref, deps) { useEffect(() => { const root = ref.current; if (!root) return; if (window.innerWidth < 1024) return; const DEBUG = (() => { try { return new URL(window.location.href).searchParams.get('debug') === '1'; } catch(_) { return false; } })(); const t0 = performance.now(); const log = (...a) => { if (DEBUG) console.log('[masonry +' + Math.round(performance.now() - t0) + 'ms]', ...a); }; const cols = () => Array.from(root.children).filter(c => c.classList && c.classList.contains('masonry-col')); let callCount = 0; const apply = (reason) => { callCount++; const list = cols(); if (list.length < 2) return; list.forEach(c => { c.style.maxHeight = ''; c.style.overflow = ''; }); const heights = list.map(c => c.getBoundingClientRect().height); const minH = Math.min(...heights); if (DEBUG) { const media = Array.from(root.querySelectorAll('img, video')); const loaded = media.filter(m => m.complete && m.naturalHeight > 0).length; log('#' + callCount + ' (' + reason + ') heights=[' + heights.map(h=>Math.round(h)).join(',') + '] minH=' + Math.round(minH) + ' media=' + loaded + '/' + media.length); } list.forEach((c, i) => { if (heights[i] > minH + 1) { c.style.maxHeight = minH + 'px'; c.style.overflow = 'hidden'; } }); }; let raf = requestAnimationFrame(() => apply('initial-raf')); const rerunWith = (reason) => () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(() => apply(reason)); }; const onLoad = rerunWith('img-load'); const onMeta = rerunWith('img-meta'); const onErr = rerunWith('img-error'); const onResize = rerunWith('resize'); const media = Array.from(root.querySelectorAll('img, video')); log('mounted: ' + media.length + ' media, ' + cols().length + ' cols, container=' + Math.round(root.getBoundingClientRect().width) + 'px'); media.forEach(m => { m.addEventListener('load', onLoad); m.addEventListener('loadedmetadata', onMeta); m.addEventListener('error', onErr); }); window.addEventListener('resize', onResize); return () => { cancelAnimationFrame(raf); media.forEach(m => { m.removeEventListener('load', onLoad); m.removeEventListener('loadedmetadata', onMeta); m.removeEventListener('error', onErr); }); window.removeEventListener('resize', onResize); }; }, deps); } // Scroll-parallax для плиток галерей (desktop-only). // Берёт каждую .tile внутри ref, считает смещение её центра от центра viewport, // прокидывает в CSS-переменную --parallax-y. CSS перетранслирует /