Files
pinboard-bundle/public/assets/pinboard.js
2026-03-04 18:50:49 +01:00

88 lines
2.1 KiB
JavaScript

(() => {
const board = document.querySelector('[data-pinboard-surface]');
if (!board) {
return;
}
if (typeof Muuri === 'undefined') {
return;
}
const notes = Array.from(board.querySelectorAll('[data-pin-note]'));
if (!notes.length) {
return;
}
let zCounter = 500;
const highlighted = notes.filter((note) => note.dataset.highlighted === '1');
const normal = notes.filter((note) => note.dataset.highlighted !== '1');
const ordered = [...highlighted, ...normal];
ordered.forEach((note) => {
board.appendChild(note);
});
ordered.forEach((note, index) => {
const isHighlighted = note.dataset.highlighted === '1';
note.style.zIndex = String(isHighlighted ? 300 + index : 100 + index);
});
const grid = new Muuri(board, {
items: '.pin-note',
dragEnabled: false,
layout: {
fillGaps: false,
horizontal: false,
alignRight: false,
alignBottom: false,
rounding: false,
},
layoutDuration: 250,
layoutEasing: 'ease',
});
const toPx = (value) => {
const parsed = Number.parseFloat(value);
return Number.isNaN(parsed) ? 0 : parsed;
};
const updateItemWidths = () => {
const boardStyles = window.getComputedStyle(board);
const boardWidth = board.clientWidth;
const gap = toPx(boardStyles.getPropertyValue('--pin-gap')) || 20;
const minItemWidth = 260;
const columns = Math.max(1, Math.floor((boardWidth + gap) / (minItemWidth + gap)));
const itemWidth = Math.max(220, Math.floor((boardWidth - (columns - 1) * gap) / columns));
ordered.forEach((note) => {
note.style.width = `${itemWidth}px`;
});
};
const bringToFront = (note) => {
zCounter += 1;
note.style.zIndex = String(zCounter);
ordered.forEach((item) => item.classList.remove('is-front'));
note.classList.add('is-front');
};
ordered.forEach((note) => {
note.addEventListener('pointerdown', () => {
bringToFront(note);
});
});
const relayout = () => {
updateItemWidths();
grid.refreshItems().layout();
};
relayout();
window.addEventListener('resize', relayout);
})();