watchlist redesign
This commit is contained in:
parent
046233817d
commit
3dad2eae38
3 changed files with 235 additions and 142 deletions
|
|
@ -1405,36 +1405,37 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
/* Inline remove buttons - compact sizing */
|
||||
.watchlist-remove-btn {
|
||||
width: auto;
|
||||
min-height: auto;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
min-width: auto;
|
||||
flex-shrink: 0;
|
||||
/* Watchlist fullscreen modal on mobile */
|
||||
.watchlist-fullscreen {
|
||||
max-width: 100vw;
|
||||
width: 100vw;
|
||||
max-height: 100vh;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Watchlist artist items */
|
||||
.watchlist-artist-item {
|
||||
padding: 12px 14px;
|
||||
gap: 10px;
|
||||
/* Watchlist card grid on mobile */
|
||||
.watchlist-artists-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.watchlist-artist-image,
|
||||
.watchlist-artist-image-placeholder {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
margin-right: 10px;
|
||||
.watchlist-card-info {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.watchlist-artist-name {
|
||||
font-size: 14px;
|
||||
.watchlist-card-name {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.watchlist-artist-date,
|
||||
.watchlist-artist-scan {
|
||||
font-size: 11px;
|
||||
.watchlist-card-meta {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Show checkbox and remove always on mobile (no hover) */
|
||||
.watchlist-card-checkbox,
|
||||
.watchlist-artist-card .watchlist-card-remove {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.watchlist-search-container {
|
||||
|
|
@ -1510,7 +1511,7 @@
|
|||
/* --- Phase 9: Touch & Hover Adaptations --- */
|
||||
|
||||
/* Global touch targets - only standalone/action buttons, not inline */
|
||||
button:not(.watchlist-remove-btn):not(.wishlist-delete-btn):not(.wishlist-delete-album-btn):not(.wishlist-delete-btn-small):not(.wishlist-back-btn):not(.alphabet-btn):not(.filter-btn):not(.playlist-modal-close) {
|
||||
button:not(.watchlist-card-remove):not(.wishlist-delete-btn):not(.wishlist-delete-album-btn):not(.wishlist-delete-btn-small):not(.wishlist-back-btn):not(.alphabet-btn):not(.filter-btn):not(.playlist-modal-close) {
|
||||
min-height: 38px;
|
||||
}
|
||||
|
||||
|
|
@ -1790,25 +1791,19 @@
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Watchlist items even tighter */
|
||||
.watchlist-artist-item {
|
||||
padding: 10px 12px;
|
||||
/* Watchlist cards — tighter grid on small screens */
|
||||
.watchlist-artists-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.watchlist-artist-image,
|
||||
.watchlist-artist-image-placeholder {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
margin-right: 8px;
|
||||
.watchlist-card-name {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.watchlist-artist-name {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.watchlist-remove-btn {
|
||||
padding: 5px 10px;
|
||||
font-size: 11px;
|
||||
.watchlist-card-info {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
/* Download modal - even more compact */
|
||||
|
|
|
|||
|
|
@ -25766,7 +25766,7 @@ async function showWatchlistModal() {
|
|||
|
||||
// Build modal content
|
||||
modal.innerHTML = `
|
||||
<div class="modal-container playlist-modal">
|
||||
<div class="modal-container playlist-modal watchlist-fullscreen">
|
||||
<div class="playlist-modal-header">
|
||||
<div class="playlist-header-content" style="width: 100%;">
|
||||
<h2>👁️ Watchlist</h2>
|
||||
|
|
@ -25814,9 +25814,9 @@ async function showWatchlistModal() {
|
|||
</div>
|
||||
<span class="playlist-modal-close" onclick="closeWatchlistModal()">×</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="playlist-modal-body">
|
||||
<div class="watchlist-actions" style="margin-bottom: 20px; display: flex; gap: 12px; align-items: center;">
|
||||
<div class="watchlist-actions" style="margin-bottom: 16px; display: flex; gap: 12px; align-items: center; padding: 0 32px; flex-wrap: wrap;">
|
||||
<button class="playlist-modal-btn playlist-modal-btn-primary"
|
||||
id="scan-watchlist-btn"
|
||||
onclick="startWatchlistScan()"
|
||||
|
|
@ -25838,14 +25838,14 @@ async function showWatchlistModal() {
|
|||
</div>
|
||||
|
||||
${globalOverrideActive ? `
|
||||
<div class="watchlist-global-override-banner">
|
||||
<div class="watchlist-global-override-banner" style="margin: 0 32px 12px;">
|
||||
<span>⚠️</span>
|
||||
<span>Global override is active — per-artist settings are being ignored during scans.</span>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="watchlist-search-container" style="margin-bottom: 16px;">
|
||||
<div class="watchlist-search-container" style="margin-bottom: 12px;">
|
||||
<input type="text"
|
||||
id="watchlist-search-input"
|
||||
class="watchlist-search-input"
|
||||
|
|
@ -25863,58 +25863,50 @@ async function showWatchlistModal() {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="watchlist-artists-list" id="watchlist-artists-list">
|
||||
<div class="watchlist-artists-grid" id="watchlist-artists-list">
|
||||
${artistsData.artists.map(artist => `
|
||||
<div class="watchlist-artist-item"
|
||||
<div class="watchlist-artist-card"
|
||||
data-artist-name="${artist.artist_name.toLowerCase().replace(/"/g, '"')}"
|
||||
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}"
|
||||
style="cursor: pointer;">
|
||||
<label class="watchlist-checkbox-wrapper" onclick="event.stopPropagation();">
|
||||
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}">
|
||||
|
||||
<label class="watchlist-card-checkbox" onclick="event.stopPropagation();">
|
||||
<input type="checkbox" class="watchlist-select-cb"
|
||||
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}"
|
||||
data-artist-name="${escapeHtml(artist.artist_name)}"
|
||||
onchange="updateWatchlistBatchBar()">
|
||||
<span class="watchlist-checkbox-custom"></span>
|
||||
</label>
|
||||
${artist.image_url ? `
|
||||
<img src="${artist.image_url}"
|
||||
alt="${escapeHtml(artist.artist_name)}"
|
||||
class="watchlist-artist-image"
|
||||
loading="lazy"
|
||||
onerror="this.style.display='none'">
|
||||
` : `
|
||||
<div class="watchlist-artist-image-placeholder">
|
||||
🎤
|
||||
</div>
|
||||
`}
|
||||
<div class="watchlist-artist-info">
|
||||
<span class="watchlist-artist-name">${escapeHtml(artist.artist_name)}</span>
|
||||
<span class="watchlist-artist-date">Added ${new Date(artist.date_added).toLocaleDateString()}</span>
|
||||
${artist.last_scan_timestamp ? `
|
||||
<span class="watchlist-artist-scan">Last scanned ${new Date(artist.last_scan_timestamp).toLocaleDateString()}</span>
|
||||
` : ''}
|
||||
</div>
|
||||
<button class="playlist-modal-btn playlist-modal-btn-secondary watchlist-remove-btn"
|
||||
|
||||
<button class="watchlist-card-remove"
|
||||
data-artist-id="${artist.spotify_artist_id || artist.itunes_artist_id}"
|
||||
data-artist-name="${escapeHtml(artist.artist_name)}"
|
||||
onclick="event.stopPropagation();">
|
||||
Remove
|
||||
</button>
|
||||
onclick="event.stopPropagation();"
|
||||
title="Remove from watchlist">×</button>
|
||||
|
||||
<div class="watchlist-card-image">
|
||||
${artist.image_url ? `
|
||||
<img src="${artist.image_url}"
|
||||
alt="${escapeHtml(artist.artist_name)}"
|
||||
loading="lazy"
|
||||
onerror="this.parentElement.innerHTML='<div class=\\'watchlist-card-image-fallback\\'>🎤</div>';">
|
||||
` : `
|
||||
<div class="watchlist-card-image-fallback">🎤</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="watchlist-card-info">
|
||||
<span class="watchlist-card-name">${escapeHtml(artist.artist_name)}</span>
|
||||
<span class="watchlist-card-meta">Added ${new Date(artist.date_added).toLocaleDateString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="playlist-modal-footer">
|
||||
<button class="playlist-modal-btn playlist-modal-btn-secondary" onclick="closeWatchlistModal()">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add event listeners for remove buttons
|
||||
modal.querySelectorAll('.watchlist-remove-btn').forEach(button => {
|
||||
modal.querySelectorAll('.watchlist-card-remove').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const artistId = button.getAttribute('data-artist-id');
|
||||
const artistName = button.getAttribute('data-artist-name');
|
||||
|
|
@ -25922,16 +25914,16 @@ async function showWatchlistModal() {
|
|||
});
|
||||
});
|
||||
|
||||
// Add click handlers to artist items (except for remove button or checkbox)
|
||||
modal.querySelectorAll('.watchlist-artist-item').forEach(item => {
|
||||
// Add click handlers to artist cards (except for remove button or checkbox)
|
||||
modal.querySelectorAll('.watchlist-artist-card').forEach(item => {
|
||||
item.addEventListener('click', (e) => {
|
||||
// Don't trigger if clicking the remove button or checkbox
|
||||
if (e.target.closest('.watchlist-remove-btn') || e.target.closest('.watchlist-checkbox-wrapper')) {
|
||||
if (e.target.closest('.watchlist-card-remove') || e.target.closest('.watchlist-card-checkbox')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const artistId = item.getAttribute('data-artist-id');
|
||||
const artistName = item.querySelector('.watchlist-artist-name').textContent;
|
||||
const artistName = item.querySelector('.watchlist-card-name').textContent;
|
||||
|
||||
console.log(`🎵 Artist card clicked: ${artistName} (${artistId})`);
|
||||
openWatchlistArtistConfigModal(artistId, artistName);
|
||||
|
|
@ -26402,13 +26394,13 @@ function filterWatchlistArtists() {
|
|||
if (!searchInput || !artistsList) return;
|
||||
|
||||
const searchTerm = searchInput.value.toLowerCase().trim();
|
||||
const artistItems = artistsList.querySelectorAll('.watchlist-artist-item');
|
||||
const artistItems = artistsList.querySelectorAll('.watchlist-artist-card');
|
||||
|
||||
artistItems.forEach(item => {
|
||||
const artistName = item.getAttribute('data-artist-name');
|
||||
|
||||
if (!searchTerm || artistName.includes(searchTerm)) {
|
||||
item.style.display = 'flex';
|
||||
item.style.display = '';
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
|
|
@ -26736,7 +26728,7 @@ async function removeFromWatchlistModal(artistId, artistName) {
|
|||
*/
|
||||
function getVisibleCheckedWatchlist() {
|
||||
return Array.from(document.querySelectorAll('.watchlist-select-cb:checked')).filter(cb => {
|
||||
const item = cb.closest('.watchlist-artist-item');
|
||||
const item = cb.closest('.watchlist-artist-card');
|
||||
return item && item.style.display !== 'none';
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8708,34 +8708,178 @@ body {
|
|||
}
|
||||
|
||||
/* Watchlist Modal Styles */
|
||||
.watchlist-artists-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
margin-top: 20px;
|
||||
padding: 30px;
|
||||
|
||||
/* Fullscreen modifier for watchlist modal */
|
||||
.watchlist-fullscreen {
|
||||
max-width: 95vw;
|
||||
width: 95vw;
|
||||
max-height: 95vh;
|
||||
}
|
||||
|
||||
.watchlist-artist-item {
|
||||
/* Override playlist-modal-body within watchlist to allow grid scrolling */
|
||||
.watchlist-fullscreen .playlist-modal-body {
|
||||
overflow-y: auto;
|
||||
padding: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* Card grid */
|
||||
.watchlist-artists-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||
gap: 24px;
|
||||
padding: 24px 32px 32px;
|
||||
}
|
||||
|
||||
/* Individual artist card */
|
||||
.watchlist-artist-card {
|
||||
position: relative;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background: rgba(18, 18, 18, 1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.watchlist-artist-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: rgba(var(--accent-rgb), 0.25);
|
||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5),
|
||||
0 0 20px rgba(var(--accent-rgb), 0.1);
|
||||
}
|
||||
|
||||
.watchlist-artist-card:active {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Image container — normal flow, sets the card height */
|
||||
.watchlist-card-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 1) 0%,
|
||||
rgba(20, 20, 20, 1) 100%);
|
||||
}
|
||||
|
||||
.watchlist-card-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Image fallback */
|
||||
.watchlist-card-image-fallback {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 20px 16px 24px;
|
||||
margin-bottom: 12px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
justify-content: center;
|
||||
font-size: 56px;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.watchlist-artist-item:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border-color: rgba(var(--accent-rgb), 0.2);
|
||||
transform: translateY(-1px);
|
||||
/* Info below the image — normal flow */
|
||||
.watchlist-card-info {
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
background: rgba(18, 18, 18, 1);
|
||||
}
|
||||
|
||||
.watchlist-card-name {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
line-height: 1.25;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.watchlist-card-meta {
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Checkbox — top-left, hidden until hover or checked */
|
||||
.watchlist-card-checkbox {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.watchlist-card-checkbox input[type="checkbox"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.watchlist-card-checkbox input:checked+.watchlist-checkbox-custom {
|
||||
background: rgba(var(--accent-rgb), 0.3);
|
||||
border-color: rgb(var(--accent-rgb));
|
||||
}
|
||||
|
||||
.watchlist-card-checkbox input:checked+.watchlist-checkbox-custom::after {
|
||||
content: '✓';
|
||||
color: rgb(var(--accent-rgb));
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.watchlist-artist-card:hover .watchlist-card-checkbox,
|
||||
.watchlist-card-checkbox:has(input:checked) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Remove × button — top-right, visible on hover */
|
||||
.watchlist-card-remove {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease, background 0.15s ease;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.watchlist-artist-card:hover .watchlist-card-remove {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.watchlist-card-remove:hover {
|
||||
background: rgba(255, 59, 48, 0.7);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* Watchlist Search */
|
||||
.watchlist-search-container {
|
||||
padding: 0 30px;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.watchlist-search-input {
|
||||
|
|
@ -8747,7 +8891,7 @@ body {
|
|||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.watchlist-search-input:focus {
|
||||
|
|
@ -8761,44 +8905,6 @@ body {
|
|||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
/* Artist Image */
|
||||
.watchlist-artist-image {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
margin-right: 16px;
|
||||
flex-shrink: 0;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.watchlist-artist-item:hover .watchlist-artist-image {
|
||||
border-color: rgba(var(--accent-rgb), 0.4);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.watchlist-artist-image-placeholder {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 50%;
|
||||
margin-right: 16px;
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.2), rgba(var(--accent-rgb), 0.05));
|
||||
border: 2px solid rgba(var(--accent-rgb), 0.3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.watchlist-artist-item:hover .watchlist-artist-image-placeholder {
|
||||
background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.3), rgba(var(--accent-rgb), 0.1));
|
||||
border-color: rgba(var(--accent-rgb), 0.5);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Watchlist & Wishlist Batch Action Bar */
|
||||
.watchlist-batch-bar,
|
||||
.wishlist-batch-bar {
|
||||
|
|
@ -8806,7 +8912,7 @@ body {
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
margin: 0 30px 12px;
|
||||
margin: 0 32px 12px;
|
||||
background: rgba(255, 59, 48, 0.1);
|
||||
border: 1px solid rgba(255, 59, 48, 0.25);
|
||||
border-radius: 10px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue