feat(admin): add bulk song selection with playlist assignment

- Introduces bulk checkboxes on the songs list page to select multiple songs
- Adds a toolbar with dropdown to add selected songs to existing playlists or create a new playlist
- Implements `/songs/bulk-add` POST endpoint for efficient batch addition of tracks to playlists
- Auto-upgrades playlist visibility when adding more-restrictive songs
- Supports preselecting songs via query parameter when creating a new playlist (`?songs=1,2,3`)
- Includes custom-styled checkboxes, toast notifications, and keyboard-friendly UI interactions
This commit is contained in:
Brian Fertig 2026-04-12 14:08:42 -06:00
parent 983b00f375
commit 31edb59583
2 changed files with 15 additions and 2 deletions

View File

@ -9,11 +9,24 @@
catch { return false; }
}
// Re-execute script tags injected via innerHTML (browser skips them otherwise).
function runScripts(container) {
container.querySelectorAll('script').forEach((old) => {
const s = document.createElement('script');
[...old.attributes].forEach((a) => s.setAttribute(a.name, a.value));
s.textContent = old.textContent;
old.replaceWith(s);
});
}
// Swap #page-shell content, update title, and optionally push history.
function applyPage(doc, finalUrl, pushState) {
const newShell = doc.getElementById('page-shell');
const curShell = document.getElementById('page-shell');
if (newShell && curShell) curShell.innerHTML = newShell.innerHTML;
if (newShell && curShell) {
curShell.innerHTML = newShell.innerHTML;
runScripts(curShell);
}
document.title = doc.title;
if (pushState) history.pushState({ btiNav: true }, doc.title, finalUrl);
window.scrollTo(0, 0);

View File

@ -138,7 +138,7 @@
const form = document.getElementById('reorder-form');
document.getElementById('reorder-order').value =
[...list.querySelectorAll('li')].map(li => li.dataset.songId).join(',');
fetch(form.action, { method: 'POST', body: new FormData(form) })
fetch(form.action, { method: 'POST', body: new URLSearchParams(new FormData(form)) })
.catch(err => console.error('[reorder] failed:', err));
});