${artistsData.artists.map(artist => `
+
${artist.image_url ? `

{
item.addEventListener('click', (e) => {
- // Don't trigger if clicking the remove button
- if (e.target.closest('.watchlist-remove-btn')) {
+ // Don't trigger if clicking the remove button or checkbox
+ if (e.target.closest('.watchlist-remove-btn') || e.target.closest('.watchlist-checkbox-wrapper')) {
return;
}
@@ -24444,6 +24461,9 @@ function filterWatchlistArtists() {
item.style.display = 'none';
}
});
+
+ // Refresh batch bar in case visible selection changed
+ updateWatchlistBatchBar();
}
/**
@@ -24759,6 +24779,73 @@ async function removeFromWatchlistModal(artistId, artistName) {
}
+/**
+ * Get visible checked checkboxes (not hidden by search filter)
+ */
+function getVisibleCheckedWatchlist() {
+ return Array.from(document.querySelectorAll('.watchlist-select-cb:checked')).filter(cb => {
+ const item = cb.closest('.watchlist-artist-item');
+ return item && item.style.display !== 'none';
+ });
+}
+
+/**
+ * Update the batch action bar based on checkbox selection
+ */
+function updateWatchlistBatchBar() {
+ const checked = getVisibleCheckedWatchlist();
+ const bar = document.getElementById('watchlist-batch-bar');
+ const countEl = document.getElementById('watchlist-batch-count');
+
+ if (checked.length > 0) {
+ bar.style.display = 'flex';
+ countEl.textContent = `${checked.length} selected`;
+ } else {
+ bar.style.display = 'none';
+ }
+}
+
+/**
+ * Batch remove selected artists from watchlist
+ */
+async function batchRemoveFromWatchlist() {
+ const checked = getVisibleCheckedWatchlist();
+ if (checked.length === 0) return;
+
+ const count = checked.length;
+ if (!confirm(`Remove ${count} artist${count !== 1 ? 's' : ''} from your watchlist?`)) return;
+
+ const artistIds = checked.map(cb => cb.getAttribute('data-artist-id'));
+
+ try {
+ const response = await fetch('/api/watchlist/remove-batch', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ artist_ids: artistIds })
+ });
+
+ const data = await response.json();
+ if (!data.success) {
+ throw new Error(data.error || 'Failed to remove artists');
+ }
+
+ console.log(`❌ Batch removed ${data.removed} artists from watchlist`);
+
+ // Refresh the modal
+ showWatchlistModal();
+
+ // Update button count
+ updateWatchlistButtonCount();
+
+ // Update any visible artist cards
+ updateArtistCardWatchlistStatus();
+
+ } catch (error) {
+ console.error('Error batch removing from watchlist:', error);
+ alert(`Error removing artists: ${error.message}`);
+ }
+}
+
// --- Metadata Updater Functions ---
// Global state for metadata update polling
diff --git a/webui/static/style.css b/webui/static/style.css
index 8a690f35..1f0c4139 100644
--- a/webui/static/style.css
+++ b/webui/static/style.css
@@ -8221,6 +8221,87 @@ body {
transform: scale(1.05);
}
+/* Watchlist Batch Action Bar */
+.watchlist-batch-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 20px;
+ margin: 0 30px 12px;
+ background: rgba(255, 59, 48, 0.1);
+ border: 1px solid rgba(255, 59, 48, 0.25);
+ border-radius: 10px;
+ animation: batchBarSlideIn 0.2s ease-out;
+}
+
+@keyframes batchBarSlideIn {
+ from { opacity: 0; transform: translateY(-8px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+.watchlist-batch-count {
+ font-size: 13px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.8);
+}
+
+.watchlist-batch-remove-btn {
+ border-color: rgba(255, 59, 48, 0.4) !important;
+ color: #ff6b6b !important;
+}
+
+.watchlist-batch-remove-btn:hover {
+ background: rgba(255, 59, 48, 0.2) !important;
+ border-color: rgba(255, 59, 48, 0.6) !important;
+}
+
+/* Watchlist Checkbox */
+.watchlist-checkbox-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 12px;
+ flex-shrink: 0;
+ cursor: pointer;
+}
+
+.watchlist-checkbox-wrapper input[type="checkbox"] {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.watchlist-checkbox-custom {
+ width: 20px;
+ height: 20px;
+ border: 2px solid rgba(255, 255, 255, 0.2);
+ border-radius: 4px;
+ background: rgba(255, 255, 255, 0.03);
+ transition: all 0.15s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.watchlist-checkbox-wrapper:hover .watchlist-checkbox-custom {
+ border-color: rgba(255, 255, 255, 0.4);
+ background: rgba(255, 255, 255, 0.06);
+}
+
+.watchlist-checkbox-wrapper input:checked + .watchlist-checkbox-custom {
+ background: rgba(29, 185, 84, 0.3);
+ border-color: #1db954;
+}
+
+.watchlist-checkbox-wrapper input:checked + .watchlist-checkbox-custom::after {
+ content: '✓';
+ color: #1db954;
+ font-size: 13px;
+ font-weight: 700;
+}
+
/* ===== WISHLIST OVERVIEW MODAL STYLES ===== */
/* Category Grid */