feat(library): bulk operations (delete / ignore)

Add a Select mode on /library: album cards become multi-select, with a bulk
bar to Delete selected (2-step confirm) or Ignore selected. POST
/api/library/bulk { action, ids } applies the op per id and reports ok/failed
counts.

Extracted the delete + ignore logic into lib/library-ops.ts
(removeLibraryItem, ignoreLibraryItem); the single DELETE route now reuses
removeLibraryItem. web 185 tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan
2026-07-14 21:37:01 +02:00
parent 8c8a34e320
commit 0f64e3c83a
6 changed files with 224 additions and 33 deletions
+6
View File
@@ -285,6 +285,12 @@ nav.contents .sep { flex: 1; }
}
.save-row { display: flex; align-items: center; gap: 14px; margin-top: 8px; }
.edit-meta { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.sel-tools { display: inline-flex; align-items: center; gap: 10px; }
.bulk-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 4px 0 12px; padding: 8px 12px; border: 1px solid var(--rule); background: var(--paper-2); }
.album-card { position: relative; }
.album-card.selected { outline: 2px solid var(--accent); outline-offset: 2px; }
.sel-check { position: absolute; top: 6px; left: 6px; z-index: 1; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; background: var(--accent); color: var(--paper); font-weight: 700; border: 1px solid var(--rule); }
.album-card:not(.selected) .sel-check { background: var(--paper-2); color: transparent; }
.settings-section { margin-bottom: 30px; }
.help { font-size: 0.8rem; color: var(--graphite); line-height: 1.5; margin: 4px 0 14px; max-width: 62ch; }
.help b { color: var(--ink); font-weight: 600; }