fix(planka): drag & drop toute colonne + filtre listes par boardId
Deploy HouseHub / deploy (push) Successful in 2s

- Drop target = toute la colonne .pk-cards (plus la zone invisible de 4px)
- Filtre les listes et cartes strictement par boardId pour éliminer les listes fantômes
- Indicateur visuel 'Déposer ici' sur colonnes vides
- CSS: colonne highlight en bleu pointillé au survol drag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
perco
2026-05-19 17:21:31 +02:00
co-authored by Claude Sonnet 4.6
parent 3516225e56
commit 285273108c
3 changed files with 41 additions and 10 deletions
+13 -2
View File
@@ -68,9 +68,20 @@ if ($action === 'board') {
$id = $_GET['id'] ?? null; if (!$id) tErr('ID manquant'); $id = $_GET['id'] ?? null; if (!$id) tErr('ID manquant');
$resp = planka_api('GET', '/api/boards/' . $id, null, $token); $resp = planka_api('GET', '/api/boards/' . $id, null, $token);
$inc = $resp['included'] ?? []; $inc = $resp['included'] ?? [];
// Filter lists that actually belong to this board (prevents ghost lists from other boards)
$lists = array_values(array_filter($inc['lists'] ?? [], fn($l) =>
isset($l['boardId']) ? $l['boardId'] === $id : true
));
// Filter cards that belong to a list in this board
$listIds = array_column($lists, 'id');
$cards = array_values(array_filter($inc['cards'] ?? [], fn($c) =>
in_array($c['listId'] ?? '', $listIds)
));
tOk([ tOk([
'lists' => $inc['lists'] ?? [], 'lists' => $lists,
'cards' => $inc['cards'] ?? [], 'cards' => $cards,
'labels' => $inc['labels'] ?? [], 'labels' => $inc['labels'] ?? [],
'members' => $inc['users'] ?? [], 'members' => $inc['users'] ?? [],
'cardLabels' => $inc['cardLabels'] ?? [], 'cardLabels' => $inc['cardLabels'] ?? [],
+19
View File
@@ -444,3 +444,22 @@
.pk-page { height: auto; overflow: visible; } .pk-page { height: auto; overflow: visible; }
.pk-board-area { overflow-x: auto; height: auto; padding-bottom: 4rem; } .pk-board-area { overflow-x: auto; height: auto; padding-bottom: 4rem; }
} }
/* ── Drag & Drop amélioré ──────────────────────────────────────────────────── */
.pk-cards.drag-over {
background: rgba(59,130,246,.07);
outline: 2px dashed var(--primary, #4361ee);
outline-offset: -2px;
border-radius: 8px;
min-height: 80px;
}
.pk-card.is-dragging { opacity: .4; }
.pk-drop-hint {
text-align: center;
color: var(--text-muted, #9ca3af);
font-size: .78rem;
padding: .75rem;
border: 2px dashed var(--border-light, #e5e7eb);
border-radius: 8px;
margin-bottom: .35rem;
}
+6 -5
View File
@@ -151,12 +151,13 @@ function renderBoard() {
area.innerHTML = sorted.map(list => renderList(list)).join(''); area.innerHTML = sorted.map(list => renderList(list)).join('');
area.querySelectorAll('.pk-card').forEach(el => { area.querySelectorAll('.pk-card').forEach(el => {
el.addEventListener('click', () => openCardModal(el.dataset.id)); el.addEventListener('click', () => openCardModal(el.dataset.id));
el.addEventListener('dragstart', e => { dragCardId = el.dataset.id; el.classList.add('is-dragging'); }); el.addEventListener('dragstart', e => { dragCardId = el.dataset.id; el.classList.add('is-dragging'); e.stopPropagation(); });
el.addEventListener('dragend', e => { el.classList.remove('is-dragging'); dragCardId = null; }); el.addEventListener('dragend', e => { el.classList.remove('is-dragging'); dragCardId = null; });
}); });
area.querySelectorAll('.pk-drop-zone').forEach(el => { // Drop target = toute la colonne .pk-cards (pas juste une zone invisible de 4px)
area.querySelectorAll('.pk-cards').forEach(el => {
el.addEventListener('dragover', e => { e.preventDefault(); el.classList.add('drag-over'); }); el.addEventListener('dragover', e => { e.preventDefault(); el.classList.add('drag-over'); });
el.addEventListener('dragleave', () => el.classList.remove('drag-over')); el.addEventListener('dragleave', e => { if (!el.contains(e.relatedTarget)) el.classList.remove('drag-over'); });
el.addEventListener('drop', e => { e.preventDefault(); el.classList.remove('drag-over'); dropCard(el.dataset.listId); }); el.addEventListener('drop', e => { e.preventDefault(); el.classList.remove('drag-over'); dropCard(el.dataset.listId); });
}); });
} }
@@ -169,8 +170,8 @@ function renderList(list) {
<span class="pk-list-name">${esc(list.name)}</span> <span class="pk-list-name">${esc(list.name)}</span>
<span class="pk-list-count">${cards.length}</span> <span class="pk-list-count">${cards.length}</span>
</div> </div>
<div class="pk-cards" id="cards-${list.id}"> <div class="pk-cards" id="cards-${list.id}" data-list-id="${list.id}">
<div class="pk-drop-zone" data-list-id="${list.id}"></div> ${cards.length === 0 ? '<div class="pk-drop-hint">Déposer ici</div>' : ''}
${cards.map(c => renderCard(c)).join('')} ${cards.map(c => renderCard(c)).join('')}
</div> </div>
<button class="pk-add-card-btn" onclick="quickAddCard('${list.id}')"> Ajouter une carte</button> <button class="pk-add-card-btn" onclick="quickAddCard('${list.id}')"> Ajouter une carte</button>