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>