css changes and lazyload changes to increase site speed.
Also fixed a docker path bug, well a potential bug.
This commit is contained in:
parent
ff3f547612
commit
1fd8e59a17
3 changed files with 73 additions and 77 deletions
|
|
@ -12993,7 +12993,7 @@ def _run_post_processing_worker(task_id, batch_id):
|
|||
return
|
||||
|
||||
download_dir = docker_resolve_path(config_manager.get('soulseek.download_path', './downloads'))
|
||||
transfer_dir = docker_resolve_path(config_manager.get('soulseek.transfer_path', './transfer'))
|
||||
transfer_dir = docker_resolve_path(config_manager.get('soulseek.transfer_path', './Transfer'))
|
||||
|
||||
# Try to get context for generating the correct final filename
|
||||
task_basename = extract_filename(task_filename)
|
||||
|
|
|
|||
|
|
@ -91,6 +91,31 @@ let artistsSearchController = null;
|
|||
let artistCompletionController = null; // Track ongoing completion check to cancel when navigating away
|
||||
let similarArtistsController = null; // Track ongoing similar artists stream to cancel when navigating away
|
||||
|
||||
// --- Lazy Background Image Observer ---
|
||||
// Watches elements with data-bg-src, applies background-image when visible, unobserves after.
|
||||
const lazyBgObserver = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
const el = entry.target;
|
||||
const src = el.dataset.bgSrc;
|
||||
if (src) {
|
||||
el.style.backgroundImage = `url('${src}')`;
|
||||
delete el.dataset.bgSrc;
|
||||
}
|
||||
lazyBgObserver.unobserve(el);
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '200px' });
|
||||
|
||||
/**
|
||||
* Observe all elements with data-bg-src within a container for lazy background loading.
|
||||
*/
|
||||
function observeLazyBackgrounds(container) {
|
||||
if (!container) return;
|
||||
const elements = container.querySelectorAll('[data-bg-src]');
|
||||
elements.forEach(el => lazyBgObserver.observe(el));
|
||||
}
|
||||
|
||||
// --- MusicBrainz Integration Constants ---
|
||||
const MUSICBRAINZ_LOGO_URL = 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png';
|
||||
|
||||
|
|
@ -6340,6 +6365,11 @@ function generateMosaicBackground(coverUrls) {
|
|||
`;
|
||||
}
|
||||
|
||||
// Cap covers per row to 15 for GPU performance (avoids hundreds of tiles)
|
||||
if (coverUrls.length > 15) {
|
||||
coverUrls = coverUrls.slice(0, 15);
|
||||
}
|
||||
|
||||
const rows = 4;
|
||||
let mosaicHTML = '<div class="wishlist-mosaic-background">';
|
||||
|
||||
|
|
@ -6359,8 +6389,8 @@ function generateMosaicBackground(coverUrls) {
|
|||
mosaicHTML += `<div class="wishlist-mosaic-row-wrapper">`;
|
||||
mosaicHTML += `<div class="wishlist-mosaic-row scroll-${direction}" style="--speed: ${scrollSpeed}s;">`;
|
||||
|
||||
// Generate tiles - duplicate 3 times for smooth infinite scroll
|
||||
for (let duplicate = 0; duplicate < 3; duplicate++) {
|
||||
// Generate tiles - duplicate 2 times for smooth infinite scroll
|
||||
for (let duplicate = 0; duplicate < 2; duplicate++) {
|
||||
for (let i = 0; i < shuffledCovers.length; i++) {
|
||||
const coverUrl = shuffledCovers[i];
|
||||
mosaicHTML += `
|
||||
|
|
@ -20075,6 +20105,7 @@ function displayArtistsResults(query, results) {
|
|||
|
||||
// Create artist cards
|
||||
container.innerHTML = results.map(result => createArtistCardHTML(result)).join('');
|
||||
observeLazyBackgrounds(container);
|
||||
|
||||
// Add event listeners to cards
|
||||
container.querySelectorAll('.artist-card').forEach((card, index) => {
|
||||
|
|
@ -20191,10 +20222,10 @@ function createArtistCardHTML(artist) {
|
|||
artist.genres.slice(0, 3).join(', ') : 'Various genres';
|
||||
const popularity = artist.popularity || 0;
|
||||
|
||||
// Create a fallback gradient if no image is available
|
||||
const backgroundStyle = imageUrl ?
|
||||
`background-image: url('${imageUrl}');` :
|
||||
`background: linear-gradient(135deg, rgba(29, 185, 84, 0.3) 0%, rgba(24, 156, 71, 0.2) 100%);`;
|
||||
// Use data-bg-src for lazy background loading via IntersectionObserver
|
||||
const backgroundAttr = imageUrl ?
|
||||
`data-bg-src="${imageUrl}"` :
|
||||
`style="background: linear-gradient(135deg, rgba(29, 185, 84, 0.3) 0%, rgba(24, 156, 71, 0.2) 100%);"`;
|
||||
|
||||
// Format popularity as a percentage for better UX
|
||||
const popularityText = popularity > 0 ? `${popularity}% Popular` : 'Popularity Unknown';
|
||||
|
|
@ -20215,7 +20246,7 @@ function createArtistCardHTML(artist) {
|
|||
return `
|
||||
<div class="artist-card" data-artist-id="${artist.id}" data-needs-image="${needsImage}">
|
||||
${mbIconHTML}
|
||||
<div class="artist-card-background" style="${backgroundStyle}"></div>
|
||||
<div class="artist-card-background" ${backgroundAttr}></div>
|
||||
<div class="artist-card-overlay"></div>
|
||||
<div class="artist-card-content">
|
||||
<div class="artist-card-name">${escapeHtml(artist.name)}</div>
|
||||
|
|
@ -20369,6 +20400,7 @@ function displayArtistDiscography(discography) {
|
|||
if (albumsContainer) {
|
||||
if (discography.albums?.length > 0) {
|
||||
albumsContainer.innerHTML = discography.albums.map(album => createAlbumCardHTML(album)).join('');
|
||||
observeLazyBackgrounds(albumsContainer);
|
||||
|
||||
// Add dynamic glow effects and click handlers to album cards
|
||||
albumsContainer.querySelectorAll('.album-card').forEach((card, index) => {
|
||||
|
|
@ -20398,6 +20430,7 @@ function displayArtistDiscography(discography) {
|
|||
if (singlesContainer) {
|
||||
if (discography.singles?.length > 0) {
|
||||
singlesContainer.innerHTML = discography.singles.map(single => createAlbumCardHTML(single)).join('');
|
||||
observeLazyBackgrounds(singlesContainer);
|
||||
|
||||
// Add dynamic glow effects and click handlers to singles cards
|
||||
singlesContainer.querySelectorAll('.album-card').forEach((card, index) => {
|
||||
|
|
@ -21082,14 +21115,14 @@ function createAlbumCardHTML(album) {
|
|||
const type = album.album_type === 'album' ? 'Album' :
|
||||
album.album_type === 'single' ? 'Single' : 'EP';
|
||||
|
||||
// Create a fallback gradient if no image is available
|
||||
const backgroundStyle = imageUrl ?
|
||||
`background-image: url('${imageUrl}');` :
|
||||
`background: linear-gradient(135deg, rgba(29, 185, 84, 0.2) 0%, rgba(24, 156, 71, 0.1) 100%);`;
|
||||
// Use data-bg-src for lazy background loading via IntersectionObserver
|
||||
const backgroundAttr = imageUrl ?
|
||||
`data-bg-src="${imageUrl}"` :
|
||||
`style="background: linear-gradient(135deg, rgba(29, 185, 84, 0.2) 0%, rgba(24, 156, 71, 0.1) 100%);"`;
|
||||
|
||||
return `
|
||||
<div class="album-card" data-album-id="${album.id}" data-album-name="${escapeHtml(album.name)}" data-album-type="${album.album_type}" data-total-tracks="${album.total_tracks || 0}">
|
||||
<div class="album-card-image" style="${backgroundStyle}"></div>
|
||||
<div class="album-card-image" ${backgroundAttr}></div>
|
||||
<div class="completion-overlay checking">
|
||||
<span class="completion-status">Checking...</span>
|
||||
</div>
|
||||
|
|
@ -24001,6 +24034,7 @@ async function showWatchlistModal() {
|
|||
<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">
|
||||
|
|
@ -24153,7 +24187,8 @@ async function openWatchlistArtistConfigModal(artistId, artistName) {
|
|||
${artist.image_url ? `
|
||||
<img src="${artist.image_url}"
|
||||
alt="${escapeHtml(artist.name)}"
|
||||
class="watchlist-artist-config-hero-image">
|
||||
class="watchlist-artist-config-hero-image"
|
||||
loading="lazy">
|
||||
` : ''}
|
||||
<div class="watchlist-artist-config-hero-info">
|
||||
<h2 class="watchlist-artist-config-hero-name">${escapeHtml(artist.name)}</h2>
|
||||
|
|
@ -25380,6 +25415,7 @@ function createLibraryArtistCard(artist) {
|
|||
const img = document.createElement("img");
|
||||
img.src = artist.image_url;
|
||||
img.alt = artist.name;
|
||||
img.loading = 'lazy';
|
||||
img.onerror = () => {
|
||||
console.log(`Failed to load image for ${artist.name}: ${artist.image_url}`);
|
||||
// Replace with fallback on error
|
||||
|
|
@ -25951,6 +25987,7 @@ function createReleaseCard(release) {
|
|||
img.src = release.image_url;
|
||||
img.alt = release.title;
|
||||
img.className = "release-image";
|
||||
img.loading = 'lazy';
|
||||
img.onerror = () => {
|
||||
imageContainer.innerHTML = `<div class="release-image-fallback">💿</div>`;
|
||||
};
|
||||
|
|
@ -29152,7 +29189,7 @@ function restoreCachedImages(genres) {
|
|||
if (genreCard) {
|
||||
const imageElement = genreCard.querySelector('.genre-browser-card-image');
|
||||
if (imageElement) {
|
||||
imageElement.innerHTML = `<img src="${genre.imageUrl}" alt="${genre.name}" style="width: 100%; height: 100%; object-fit: cover;">`;
|
||||
imageElement.innerHTML = `<img src="${genre.imageUrl}" alt="${genre.name}" loading="lazy" style="width: 100%; height: 100%; object-fit: cover;">`;
|
||||
genreCard.classList.remove('genre-browser-card-fallback');
|
||||
}
|
||||
}
|
||||
|
|
@ -29202,7 +29239,7 @@ async function loadGenreBrowserImagesProgressively(genres) {
|
|||
const imageElement = genreCard.querySelector('.genre-browser-card-image');
|
||||
if (imageElement) {
|
||||
// Replace the fallback emoji with the actual image
|
||||
imageElement.innerHTML = `<img src="${data.image_url}" alt="${genre.name}" style="width: 100%; height: 100%; object-fit: cover;">`;
|
||||
imageElement.innerHTML = `<img src="${data.image_url}" alt="${genre.name}" loading="lazy" style="width: 100%; height: 100%; object-fit: cover;">`;
|
||||
genreCard.classList.remove('genre-browser-card-fallback');
|
||||
|
||||
console.log(`✅ Loaded and cached image for ${genre.name} in modal`);
|
||||
|
|
@ -31020,7 +31057,7 @@ async function loadDiscoverRecentReleases() {
|
|||
html += `
|
||||
<div class="discover-card" onclick="openDownloadModalForRecentAlbum(${index})" style="cursor: pointer;">
|
||||
<div class="discover-card-image">
|
||||
<img src="${coverUrl}" alt="${album.album_name}">
|
||||
<img src="${coverUrl}" alt="${album.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="discover-card-info">
|
||||
<h4 class="discover-card-title">${album.album_name}</h4>
|
||||
|
|
@ -31075,7 +31112,7 @@ async function loadDiscoverReleaseRadar() {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${track.album_name}">
|
||||
<img src="${coverUrl}" alt="${track.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${track.track_name}</div>
|
||||
|
|
@ -31132,7 +31169,7 @@ async function loadDiscoverWeekly() {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${track.album_name}">
|
||||
<img src="${coverUrl}" alt="${track.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${track.track_name}</div>
|
||||
|
|
@ -31608,7 +31645,7 @@ async function loadDecadeTracks(decade) {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${albumName}">
|
||||
<img src="${coverUrl}" alt="${albumName}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${trackName}</div>
|
||||
|
|
@ -31977,7 +32014,7 @@ async function loadGenreTracks(genreName) {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${albumName}">
|
||||
<img src="${coverUrl}" alt="${albumName}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${trackName}</div>
|
||||
|
|
@ -32622,7 +32659,7 @@ function displayListenBrainzTracks(tracks, playlistId) {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${albumName}" onerror="this.src='${placeholderImage}'">
|
||||
<img src="${coverUrl}" alt="${albumName}" loading="lazy" onerror="this.src='${placeholderImage}'">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${escapeHtml(track.track_name || 'Unknown Track')}</div>
|
||||
|
|
@ -33036,7 +33073,7 @@ async function loadSeasonalAlbums(seasonData) {
|
|||
html += `
|
||||
<div class="discover-card" onclick="openDownloadModalForSeasonalAlbum(${index})" style="cursor: pointer;">
|
||||
<div class="discover-card-image">
|
||||
<img src="${coverUrl}" alt="${album.album_name}">
|
||||
<img src="${coverUrl}" alt="${album.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="discover-card-info">
|
||||
<h4 class="discover-card-title">${album.album_name}</h4>
|
||||
|
|
@ -33106,7 +33143,7 @@ async function loadSeasonalPlaylist(seasonData) {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${track.album_name}">
|
||||
<img src="${coverUrl}" alt="${track.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${track.track_name}</div>
|
||||
|
|
@ -33415,7 +33452,7 @@ async function loadPersonalizedDailyMixes() {
|
|||
html += `
|
||||
<div class="discover-playlist-card" onclick="openDailyMix(${index})">
|
||||
<div class="discover-playlist-cover">
|
||||
<img src="${coverUrl}" alt="${mix.name}">
|
||||
<img src="${coverUrl}" alt="${mix.name}" loading="lazy">
|
||||
<div class="playlist-play-overlay">▶</div>
|
||||
</div>
|
||||
<div class="discover-playlist-info">
|
||||
|
|
@ -33448,7 +33485,7 @@ function renderCompactPlaylist(container, tracks) {
|
|||
<div class="discover-playlist-track-compact" data-track-index="${index}">
|
||||
<div class="track-compact-number">${index + 1}</div>
|
||||
<div class="track-compact-image">
|
||||
<img src="${coverUrl}" alt="${track.album_name}">
|
||||
<img src="${coverUrl}" alt="${track.album_name}" loading="lazy">
|
||||
</div>
|
||||
<div class="track-compact-info">
|
||||
<div class="track-compact-name">${track.track_name}</div>
|
||||
|
|
@ -33547,7 +33584,7 @@ async function searchBuildPlaylistArtists() {
|
|||
const imageUrl = artist.image_url || '/static/placeholder-album.png';
|
||||
html += `
|
||||
<div class="build-playlist-search-result" onclick="addBuildPlaylistArtist('${artist.id}', '${artist.name.replace(/'/g, "\\'")}', '${imageUrl}')">
|
||||
<img src="${imageUrl}" alt="${artist.name}">
|
||||
<img src="${imageUrl}" alt="${artist.name}" loading="lazy">
|
||||
<span>${artist.name}</span>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -33611,7 +33648,7 @@ function renderBuildPlaylistSelectedArtists() {
|
|||
buildPlaylistSelectedArtists.forEach(artist => {
|
||||
html += `
|
||||
<div class="build-playlist-selected-artist">
|
||||
<img src="${artist.image_url}" alt="${artist.name}">
|
||||
<img src="${artist.image_url}" alt="${artist.name}" loading="lazy">
|
||||
<span>${artist.name}</span>
|
||||
<button onclick="removeBuildPlaylistArtist('${artist.id}')" class="build-playlist-remove-artist">×</button>
|
||||
</div>
|
||||
|
|
@ -35041,7 +35078,7 @@ async function loadImportSuggestions() {
|
|||
section.classList.remove('hidden');
|
||||
grid.innerHTML = data.suggestions.map(a => `
|
||||
<div class="import-album-card" onclick="selectImportAlbum('${a.id}')">
|
||||
<img src="${a.image_url || '/static/placeholder.png'}" alt="${a.name}" onerror="this.src='/static/placeholder.png'">
|
||||
<img src="${a.image_url || '/static/placeholder.png'}" alt="${a.name}" loading="lazy" onerror="this.src='/static/placeholder.png'">
|
||||
<div class="import-album-card-info">
|
||||
<div class="import-album-card-title" title="${a.name}">${a.name}</div>
|
||||
<div class="import-album-card-artist" title="${a.artist}">${a.artist}</div>
|
||||
|
|
@ -35074,7 +35111,7 @@ async function searchImportAlbum() {
|
|||
}
|
||||
grid.innerHTML = data.albums.map(a => `
|
||||
<div class="import-album-card" onclick="selectImportAlbum('${a.id}')">
|
||||
<img src="${a.image_url || '/static/placeholder.png'}" alt="${a.name}" onerror="this.src='/static/placeholder.png'">
|
||||
<img src="${a.image_url || '/static/placeholder.png'}" alt="${a.name}" loading="lazy" onerror="this.src='/static/placeholder.png'">
|
||||
<div class="import-album-card-info">
|
||||
<div class="import-album-card-title" title="${a.name}">${a.name}</div>
|
||||
<div class="import-album-card-artist" title="${a.artist}">${a.artist}</div>
|
||||
|
|
@ -35126,7 +35163,7 @@ async function selectImportAlbum(albumId) {
|
|||
// Render hero
|
||||
const album = data.album;
|
||||
document.getElementById('import-album-hero').innerHTML = `
|
||||
<img src="${album.image_url || '/static/placeholder.png'}" alt="${album.name}" onerror="this.src='/static/placeholder.png'">
|
||||
<img src="${album.image_url || '/static/placeholder.png'}" alt="${album.name}" loading="lazy" onerror="this.src='/static/placeholder.png'">
|
||||
<div class="import-album-hero-info">
|
||||
<h3>${album.name}</h3>
|
||||
<p>${album.artist} · ${album.total_tracks} tracks · ${album.release_date ? album.release_date.substring(0,4) : ''}</p>
|
||||
|
|
|
|||
|
|
@ -161,8 +161,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.06) 0%,
|
||||
rgba(255, 255, 255, 0.03) 100%);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
transform: translateX(4px);
|
||||
box-shadow:
|
||||
|
|
@ -175,8 +173,6 @@ body {
|
|||
rgba(29, 185, 84, 0.16) 0%,
|
||||
rgba(29, 185, 84, 0.12) 50%,
|
||||
rgba(29, 185, 84, 0.08) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.6);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(1.6);
|
||||
border: 1px solid rgba(29, 185, 84, 0.25);
|
||||
transform: translateX(6px);
|
||||
box-shadow:
|
||||
|
|
@ -191,8 +187,6 @@ body {
|
|||
rgba(29, 185, 84, 0.22) 0%,
|
||||
rgba(29, 185, 84, 0.18) 50%,
|
||||
rgba(29, 185, 84, 0.12) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.8);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(1.8);
|
||||
border: 1px solid rgba(29, 185, 84, 0.35);
|
||||
transform: translateX(8px);
|
||||
box-shadow:
|
||||
|
|
@ -214,8 +208,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.08) 0%,
|
||||
rgba(255, 255, 255, 0.04) 100%);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
|
@ -229,8 +221,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(29, 185, 84, 0.25) 0%,
|
||||
rgba(30, 215, 96, 0.20) 100%);
|
||||
backdrop-filter: blur(10px) saturate(1.6);
|
||||
-webkit-backdrop-filter: blur(10px) saturate(1.6);
|
||||
border: 1px solid rgba(29, 185, 84, 0.3);
|
||||
font-weight: 700;
|
||||
box-shadow:
|
||||
|
|
@ -996,8 +986,6 @@ body {
|
|||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, rgba(29, 185, 84, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.5);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(1.5);
|
||||
border: 1px solid rgba(29, 185, 84, 0.15);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
|
|
@ -1087,8 +1075,6 @@ body {
|
|||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
backdrop-filter: blur(12px) saturate(1.1);
|
||||
-webkit-backdrop-filter: blur(12px) saturate(1.1);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
|
@ -3507,7 +3493,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(12px) saturate(1.1);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
|
|
@ -3540,7 +3525,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(16px) saturate(1.2);
|
||||
border-color: rgba(29, 185, 84, 0.3);
|
||||
border-top-color: rgba(29, 185, 84, 0.4);
|
||||
|
||||
|
|
@ -3612,7 +3596,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(12px) saturate(1.1);
|
||||
border-radius: 24px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
|
|
@ -3642,7 +3625,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(16px) saturate(1.2);
|
||||
border-color: rgba(29, 185, 84, 0.3);
|
||||
border-top-color: rgba(29, 185, 84, 0.4);
|
||||
|
||||
|
|
@ -3746,7 +3728,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.03) 0%,
|
||||
rgba(255, 255, 255, 0.01) 100%);
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
padding: 12px;
|
||||
|
|
@ -3767,7 +3748,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(255, 255, 255, 0.06) 0%,
|
||||
rgba(255, 255, 255, 0.02) 100%);
|
||||
backdrop-filter: blur(10px);
|
||||
border-color: rgba(29, 185, 84, 0.2);
|
||||
|
||||
/* Enhanced subtle depth */
|
||||
|
|
@ -4281,10 +4261,8 @@ body {
|
|||
|
||||
/* Apple-style liquid glassmorphic foundation */
|
||||
background: linear-gradient(135deg,
|
||||
rgba(20, 20, 20, 0.55) 0%,
|
||||
rgba(12, 12, 12, 0.65) 100%);
|
||||
backdrop-filter: blur(40px) saturate(1.8);
|
||||
-webkit-backdrop-filter: blur(40px) saturate(1.8);
|
||||
rgba(20, 20, 20, 0.85) 0%,
|
||||
rgba(12, 12, 12, 0.92) 100%);
|
||||
border-radius: 24px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
|
|
@ -4439,7 +4417,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(20, 20, 20, 0.95) 0%,
|
||||
rgba(12, 12, 12, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.18);
|
||||
|
|
@ -4551,7 +4528,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(20, 20, 20, 0.95) 0%,
|
||||
rgba(12, 12, 12, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.18);
|
||||
|
|
@ -4611,7 +4587,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(20, 20, 20, 0.95) 0%,
|
||||
rgba(12, 12, 12, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.18);
|
||||
|
|
@ -5064,7 +5039,6 @@ body {
|
|||
.sync-main-panel,
|
||||
.sync-sidebar {
|
||||
background: linear-gradient(135deg, rgba(26, 26, 26, 0.95), rgba(18, 18, 18, 0.98));
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
padding: 20px;
|
||||
|
|
@ -5543,7 +5517,6 @@ body {
|
|||
border: none;
|
||||
border-radius: 50%;
|
||||
background: rgba(1, 255, 149, 0.2);
|
||||
backdrop-filter: blur(10px);
|
||||
color: #01FF95;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
|
|
@ -5654,7 +5627,6 @@ body {
|
|||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 50%,
|
||||
rgba(12, 12, 12, 0.99) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
/* Enhanced borders matching modal hero */
|
||||
border: 1px solid rgba(1, 255, 149, 0.3);
|
||||
|
|
@ -5779,7 +5751,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 20px;
|
||||
|
|
@ -5818,7 +5789,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
transform: translateY(-6px) scale(1.02);
|
||||
border-color: rgba(1, 255, 149, 0.4);
|
||||
|
|
@ -5911,7 +5881,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 16px;
|
||||
|
|
@ -5980,7 +5949,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 16px;
|
||||
|
|
@ -6022,7 +5990,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
border-color: rgba(1, 255, 149, 0.4);
|
||||
|
|
@ -6300,7 +6267,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(20, 20, 20, 0.95) 0%,
|
||||
rgba(12, 12, 12, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders */
|
||||
border-radius: 20px;
|
||||
|
|
@ -6344,7 +6310,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 16px;
|
||||
|
|
@ -6386,7 +6351,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
border-color: rgba(1, 255, 149, 0.4);
|
||||
|
|
@ -6623,7 +6587,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 16px;
|
||||
|
|
@ -6662,7 +6625,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
border-color: rgba(138, 43, 226, 0.5);
|
||||
|
|
@ -6855,7 +6817,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(20px) saturate(1.2);
|
||||
|
||||
/* Enhanced borders matching modal */
|
||||
border-radius: 16px;
|
||||
|
|
@ -6894,7 +6855,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(24px) saturate(1.3);
|
||||
|
||||
transform: translateY(-6px) scale(1.02);
|
||||
border-color: rgba(138, 43, 226, 0.5);
|
||||
|
|
@ -7229,7 +7189,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(26, 26, 26, 0.95) 0%,
|
||||
rgba(18, 18, 18, 0.98) 100%);
|
||||
backdrop-filter: blur(12px) saturate(1.1);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
|
|
@ -7253,7 +7212,6 @@ body {
|
|||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.98) 0%,
|
||||
rgba(22, 22, 22, 1.0) 100%);
|
||||
backdrop-filter: blur(16px) saturate(1.2);
|
||||
border-color: rgba(29, 185, 84, 0.3);
|
||||
border-top-color: rgba(29, 185, 84, 0.4);
|
||||
|
||||
|
|
@ -8316,6 +8274,7 @@ body {
|
|||
height: 100%;
|
||||
opacity: 0;
|
||||
animation: fadeInRow 1s ease-out forwards, infiniteScroll var(--speed, 30s) linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.wishlist-mosaic-row.scroll-right {
|
||||
|
|
@ -8400,14 +8359,14 @@ body {
|
|||
}
|
||||
|
||||
/* Infinite scrolling animation */
|
||||
/* Content is duplicated 3x, animation moves by -33.333% (one set) for seamless loop */
|
||||
/* Content is duplicated 2x, animation moves by -50% (one set) for seamless loop */
|
||||
@keyframes infiniteScroll {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-33.333%);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue