web/wp-content/themes/mozilla-builders/static/js/plugins/masonry.js (27 lines of code) (raw):

/** @type {import('alpinejs').PluginCallback} */ export function masonry(Alpine) { Alpine.directive('masonry', (el, { expression }, { cleanup }) => { const unregister = registerRoot(el, expression); cleanup(() => unregister()); }); } const BREAKPOINTS = { sm: 640, md: 768, lg: 1024, xl: 1280, '2xl': 1536, }; /** * Register the root element for masonry layout * * @param {HTMLElement} el - The root element * @param {string} [screen] - The screen size to use (default: md) */ function registerRoot(el, screen) { const breakpoint = BREAKPOINTS[screen ?? 'md'] ?? BREAKPOINTS.md; const rowHeight = 10; const rowGap = parseInt(window.getComputedStyle(el).getPropertyValue('grid-row-gap')); function resize() { if (window.innerWidth >= breakpoint) { el.style.gridAutoRows = `${rowHeight}px`; Array.from(el.children).forEach(item => { const itemContent = item.children[0]; if (!itemContent) { item.style.gridRowEnd = 'auto'; } else { const { height } = itemContent.getBoundingClientRect(); const rowSpan = Math.ceil((height + rowGap) / (rowHeight + rowGap)); item.style.gridRowEnd = `span ${rowSpan}`; } }); } else { el.style.gridAutoRows = 'auto'; Array.from(el.children).forEach(item => { item.style.gridRowEnd = 'auto'; }); } } resize(); window.addEventListener('resize', resize); return () => { window.removeEventListener('resize', resize); el.style.gridAutoRows = 'auto'; Array.from(el.children).forEach(item => { item.style.gridRowEnd = 'auto'; }); }; }