feat: larger moodboard cards (220px) + mouse wheel zoom on images

- Cards wider for better visual presence
- Scroll wheel zooms in/out (100-400%)
- Drag sensitivity adjusts with zoom level
- Zoom level persisted per image

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Etienne Delvarre
2026-05-29 14:48:43 +02:00
parent e896d91681
commit 405a249ed0
+15 -3
View File
@@ -289,7 +289,7 @@ window.dispatchEvent(new Event('tiptap-loaded'));
.list-item-expand { font-size: 12px; color: var(--text-hint); cursor: pointer; margin-left: 8px; white-space: nowrap; } .list-item-expand { font-size: 12px; color: var(--text-hint); cursor: pointer; margin-left: 8px; white-space: nowrap; }
.list-item-expand:hover { color: var(--accent); } .list-item-expand:hover { color: var(--accent); }
.mood-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 16px; } .mood-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px; }
.mood-card { position: relative; border-radius: 10px; overflow: hidden; background: var(--bg-alt); border: 1px solid var(--border); } .mood-card { position: relative; border-radius: 10px; overflow: hidden; background: var(--bg-alt); border: 1px solid var(--border); }
.mood-card-img { width: 100%; aspect-ratio: 1; background-size: cover; background-position: center; cursor: pointer; background-color: var(--bg-alt); display: flex; align-items: center; justify-content: center; user-select: none; } .mood-card-img { width: 100%; aspect-ratio: 1; background-size: cover; background-position: center; cursor: pointer; background-color: var(--bg-alt); display: flex; align-items: center; justify-content: center; user-select: none; }
.mood-card-img.has-image { cursor: grab; } .mood-card-img.has-image { cursor: grab; }
@@ -1222,7 +1222,9 @@ function renderMoodboard() {
const hasImg = !!item.image; const hasImg = !!item.image;
imgDiv.className = 'mood-card-img' + (hasImg ? ' has-image' : ' empty'); imgDiv.className = 'mood-card-img' + (hasImg ? ' has-image' : ' empty');
if (hasImg) { if (hasImg) {
const zoom = item.zoom ?? 100;
imgDiv.style.backgroundImage = `url(${item.image})`; imgDiv.style.backgroundImage = `url(${item.image})`;
imgDiv.style.backgroundSize = `${zoom}%`;
imgDiv.style.backgroundPosition = `${item.posX ?? 50}% ${item.posY ?? 50}%`; imgDiv.style.backgroundPosition = `${item.posX ?? 50}% ${item.posY ?? 50}%`;
} }
if (!hasImg) { if (!hasImg) {
@@ -1235,8 +1237,9 @@ function renderMoodboard() {
if (!didDrag && Math.abs(dx) < 4 && Math.abs(dy) < 4) return; if (!didDrag && Math.abs(dx) < 4 && Math.abs(dy) < 4) return;
didDrag = true; didDrag = true;
const rect = imgDiv.getBoundingClientRect(); const rect = imgDiv.getBoundingClientRect();
item.posX = Math.max(0, Math.min(100, startPosX + (dx / rect.width) * -80)); const scale = (item.zoom ?? 100) / 100;
item.posY = Math.max(0, Math.min(100, startPosY + (dy / rect.height) * -80)); item.posX = Math.max(0, Math.min(100, startPosX + (dx / rect.width) * -80 / scale));
item.posY = Math.max(0, Math.min(100, startPosY + (dy / rect.height) * -80 / scale));
imgDiv.style.backgroundPosition = `${item.posX}% ${item.posY}%`; imgDiv.style.backgroundPosition = `${item.posX}% ${item.posY}%`;
}; };
const onUp = () => { const onUp = () => {
@@ -1255,6 +1258,14 @@ function renderMoodboard() {
window.addEventListener('mousemove', onMove); window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onUp); window.addEventListener('mouseup', onUp);
}); });
// Scroll to zoom
imgDiv.addEventListener('wheel', (e) => {
e.preventDefault();
const delta = e.deltaY > 0 ? -10 : 10;
item.zoom = Math.max(100, Math.min(400, (item.zoom ?? 100) + delta));
imgDiv.style.backgroundSize = `${item.zoom}%`;
saveVisionSection('moodboard', JSON.stringify(items));
}, { passive: false });
imgDiv.addEventListener('dblclick', () => { moodUploadTarget = i; document.getElementById('mood-file-input').click(); }); imgDiv.addEventListener('dblclick', () => { moodUploadTarget = i; document.getElementById('mood-file-input').click(); });
} }
@@ -1326,6 +1337,7 @@ document.addEventListener('DOMContentLoaded', () => {
items[moodUploadTarget].image = data.path; items[moodUploadTarget].image = data.path;
items[moodUploadTarget].posX = 50; items[moodUploadTarget].posX = 50;
items[moodUploadTarget].posY = 50; items[moodUploadTarget].posY = 50;
items[moodUploadTarget].zoom = 100;
saveVisionSection('moodboard', JSON.stringify(items)); saveVisionSection('moodboard', JSON.stringify(items));
renderMoodboard(); renderMoodboard();
} }