Add justified photo grid layout with lazy loading and image dimensions.
This commit is contained in:
parent
3efa217716
commit
687445e414
4 changed files with 147 additions and 3 deletions
75
photologue/static/gallery_justified.js
Normal file
75
photologue/static/gallery_justified.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Justified photo grid layout (Google Photos style)
|
||||
// Inspired by https://github.com/flickr/justified-layout
|
||||
(function () {
|
||||
const SPACING = 3;
|
||||
const PADDING = 3;
|
||||
|
||||
function applyLayout() {
|
||||
const container = document.getElementById('lightgallery');
|
||||
if (!container) return;
|
||||
|
||||
const items = [...container.querySelectorAll('.photo-item')];
|
||||
if (!items.length) return;
|
||||
|
||||
const containerWidth = container.offsetWidth - PADDING * 2;
|
||||
const TARGET_HEIGHT = Math.min(220, Math.floor(containerWidth * 0.4));
|
||||
const ratios = items.map(a => {
|
||||
const w = parseInt(a.dataset.width) || 1;
|
||||
const h = parseInt(a.dataset.height) || 1;
|
||||
return w / h;
|
||||
});
|
||||
|
||||
// Group items into rows
|
||||
const rows = [];
|
||||
let rowStart = 0;
|
||||
while (rowStart < ratios.length) {
|
||||
let sum = 0;
|
||||
let end = rowStart;
|
||||
while (end < ratios.length) {
|
||||
sum += ratios[end];
|
||||
const rowWidth = sum * TARGET_HEIGHT + SPACING * (end - rowStart);
|
||||
end++;
|
||||
if (rowWidth >= containerWidth) break;
|
||||
}
|
||||
rows.push({ start: rowStart, end });
|
||||
rowStart = end;
|
||||
}
|
||||
|
||||
// Position each item
|
||||
let top = PADDING;
|
||||
rows.forEach(({ start, end }, rowIndex) => {
|
||||
const isLastRow = rowIndex === rows.length - 1;
|
||||
const count = end - start;
|
||||
const sumRatios = ratios.slice(start, end).reduce((a, b) => a + b, 0);
|
||||
const totalSpacing = SPACING * (count - 1);
|
||||
|
||||
// Don't stretch the last row if it's not full
|
||||
const rowHeight = isLastRow && count < 3
|
||||
? TARGET_HEIGHT
|
||||
: (containerWidth - totalSpacing) / sumRatios;
|
||||
|
||||
let left = PADDING;
|
||||
for (let i = start; i < end; i++) {
|
||||
const width = Math.round(ratios[i] * rowHeight);
|
||||
const height = Math.round(rowHeight);
|
||||
const item = items[i];
|
||||
item.style.top = top + 'px';
|
||||
item.style.left = left + 'px';
|
||||
item.style.width = width + 'px';
|
||||
item.style.height = height + 'px';
|
||||
left += width + SPACING;
|
||||
}
|
||||
top += Math.round(rowHeight) + SPACING;
|
||||
});
|
||||
|
||||
container.style.height = (top - SPACING + PADDING) + 'px';
|
||||
items.forEach(item => {
|
||||
item.style.visibility = 'visible';
|
||||
const img = item.querySelector('img[data-lazy]');
|
||||
if (img) img.src = img.dataset.lazy;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', applyLayout);
|
||||
window.addEventListener('resize', applyLayout);
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue