Widget:Masonry

From The Museum of Human Achievement
<style>
#masonry {
 display: flex;
 flex-wrap: wrap;
 gap: 8px;
 justify-content: start;
}
#masonry .tile {
 height: px;
 overflow: hidden;
 border-radius: 0;
 display: flex;
 align-items: center;
 justify-content: center;
 background-size: cover;
 background-position: center;
 flex: auto;
}
#masonry .tile:last-of-type {
 flex: 0 auto !important;
}
#masonry .tile a {
 display: block;
 width: 100%;
 height: 100%;
}
</style>
<script>
function buildMediaViewerUrl(fileName) {
  const pageUrl = window.location.origin + window.location.pathname;
  const fileTitle = 'File:' + fileName;
  return pageUrl + '#mediaviewer/' + fileTitle;
}
(async () => {
 const wall = document.getElementById('masonry');
 const tiles = Array.from(wall.querySelectorAll('.tile'));
 if (!tiles.length) return;
 const tileHeight = parseFloat(getComputedStyle(tiles[0]).height); // px
 // Helper: load an image and resolve with its natural dimensions
 function loadImg(url) {
   return new Promise((resolve, reject) => {
     const img = new Image();
     img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight });
     img.onerror = reject;
     img.src = url;
   });
 }
 // Load all images in parallel
 await Promise.all(tiles.map(async (t) => {
   const url = t.dataset.bg;
   const parts   = url.split('/');
   const file    = parts[parts.length - 1].replace(/\/+$/, );
   const url2    = buildMediaViewerUrl(file);
   try {
     const { width, height } = await loadImg(url);
     const ratio = width / height;               // image aspect ratio
     const computedWidth = tileHeight * ratio;   // keep the same height
     t.style.backgroundImage = `url(${url})`;
     t.style.width = `${computedWidth}px`;       // set width based on its own ratio
     const link = document.createElement('a');
     link.href = url2;            // open the image itself
     link.target = '_blank';     // new tab
     link.rel = 'noopener noreferrer';
     t.appendChild(link);
   } catch (e) {
     console.error('Failed to load image', url, e);
   }
 }));
})();
</script>