beatport progress
This commit is contained in:
parent
f7119b7319
commit
5981bd772f
3 changed files with 260 additions and 226 deletions
192
webui/index.html
192
webui/index.html
|
|
@ -409,61 +409,104 @@
|
|||
</div>
|
||||
|
||||
<div class="beatport-navigation">
|
||||
<!-- Main Category Cards View -->
|
||||
<!-- New Homepage Main View -->
|
||||
<div class="beatport-main-view active" id="beatport-main-view">
|
||||
<div class="beatport-category-cards">
|
||||
<div class="beatport-category-card" data-category="top-charts">
|
||||
<div class="category-icon top-charts-icon"></div>
|
||||
<h3>🔥 Top Charts</h3>
|
||||
<p>Beatport Top 100, Top 100 New Releases, Hype Top 100</p>
|
||||
<span class="category-count">3 Charts</span>
|
||||
</div>
|
||||
|
||||
<div class="beatport-category-card" data-category="genres">
|
||||
<div class="category-icon genres-icon"></div>
|
||||
<h3>🎵 Genre Explorer</h3>
|
||||
<p>House, Techno, Trance, and 36 more genres</p>
|
||||
<span class="category-count">39 Genres</span>
|
||||
</div>
|
||||
|
||||
<div class="beatport-category-card" data-category="staff-picks">
|
||||
<div class="category-icon staff-picks-icon"></div>
|
||||
<h3>📊 Staff Picks</h3>
|
||||
<p>Curated selections and secret weapons</p>
|
||||
<span class="category-count">5 Collections</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Charts Sub-View -->
|
||||
<div class="beatport-sub-view" id="beatport-top-charts-view">
|
||||
<div class="beatport-breadcrumb">
|
||||
<button class="breadcrumb-back">← Back to Categories</button>
|
||||
<span class="breadcrumb-path">Browse Charts > Top Charts</span>
|
||||
</div>
|
||||
<div class="beatport-chart-list">
|
||||
<div class="beatport-chart-item" data-chart-type="top-100" data-chart-id="top-100" data-chart-name="Beatport Top 100" data-chart-endpoint="/api/beatport/top-100">
|
||||
<div class="chart-icon">🏆</div>
|
||||
<div class="chart-info">
|
||||
<h3>Beatport Top 100</h3>
|
||||
<p>The hottest electronic tracks right now</p>
|
||||
<span class="track-count">100 tracks</span>
|
||||
<!-- Genre Explorer Section -->
|
||||
<div class="homepage-genre-section">
|
||||
<h3 class="section-title">🎵 Genre Explorer</h3>
|
||||
<div class="genre-chart-types-grid">
|
||||
<div class="genre-chart-type-card" data-action="show-genres">
|
||||
<div class="chart-type-icon">🎵</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Browse All Genres</h3>
|
||||
<p>House, Techno, Trance, and 36 more genres</p>
|
||||
<span class="track-count">39 Genres</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="top-100-releases" data-chart-id="top-100-releases" data-chart-name="Top 100 New Releases" data-chart-endpoint="/api/beatport/top-100-releases">
|
||||
<div class="chart-icon">📀</div>
|
||||
<div class="chart-info">
|
||||
<h3>Top 100 New Releases</h3>
|
||||
<p>Newest and most popular releases on Beatport</p>
|
||||
<span class="track-count">100 tracks</span>
|
||||
</div>
|
||||
|
||||
<!-- Main Charts Section -->
|
||||
<div class="homepage-main-charts-section">
|
||||
<h3 class="section-title">📊 Main Charts</h3>
|
||||
<div class="genre-chart-types-grid">
|
||||
<div class="genre-chart-type-card" data-chart-type="top-10" data-chart-endpoint="/api/beatport/top-100">
|
||||
<div class="chart-type-icon">🔥</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Beatport Top 10</h3>
|
||||
<p>Current hottest tracks</p>
|
||||
<span class="track-count">10 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="genre-chart-type-card" data-chart-type="top-100" data-chart-endpoint="/api/beatport/top-100">
|
||||
<div class="chart-type-icon">💯</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Beatport Top 100</h3>
|
||||
<p>Complete chart rankings</p>
|
||||
<span class="track-count">100 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="hype" data-chart-id="hype-10" data-chart-name="Hype Top 100" data-chart-endpoint="/api/beatport/hype-top-100">
|
||||
<div class="chart-icon">🚀</div>
|
||||
<div class="chart-info">
|
||||
<h3>Hype Top 100</h3>
|
||||
<p>Rising stars and breakthrough tracks</p>
|
||||
<span class="track-count">100 tracks</span>
|
||||
</div>
|
||||
|
||||
<!-- Releases Section -->
|
||||
<div class="homepage-releases-section">
|
||||
<h3 class="section-title">🎵 Releases</h3>
|
||||
<div class="genre-chart-types-grid">
|
||||
<div class="genre-chart-type-card" data-chart-type="releases-top-10" data-chart-endpoint="/api/beatport/homepage/releases-top-10">
|
||||
<div class="chart-type-icon">🆕</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Top 10 Releases</h3>
|
||||
<p>Newest releases trending</p>
|
||||
<span class="track-count">10 releases</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="genre-chart-type-card" data-chart-type="releases-top-100" data-chart-endpoint="/api/beatport/top-100-releases">
|
||||
<div class="chart-type-icon">📊</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Top 100 Releases</h3>
|
||||
<p>All trending releases</p>
|
||||
<span class="track-count">100 releases</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="genre-chart-type-card" data-chart-type="latest-releases" data-chart-endpoint="/api/beatport/homepage/latest-releases">
|
||||
<div class="chart-type-icon">🕒</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Latest Releases</h3>
|
||||
<p>Recently published</p>
|
||||
<span class="track-count">50 releases</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hype Section -->
|
||||
<div class="homepage-hype-section">
|
||||
<h3 class="section-title">🔥 Hype</h3>
|
||||
<div class="genre-chart-types-grid">
|
||||
<div class="genre-chart-type-card" data-chart-type="hype-top-10" data-chart-endpoint="/api/beatport/homepage/hype-top-10">
|
||||
<div class="chart-type-icon">🚀</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Hype Top 10</h3>
|
||||
<p>Hottest trending tracks</p>
|
||||
<span class="track-count">10 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="genre-chart-type-card" data-chart-type="hype-top-100" data-chart-endpoint="/api/beatport/hype-top-100">
|
||||
<div class="chart-type-icon">🔥</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Hype Top 100</h3>
|
||||
<p>Complete hype chart rankings</p>
|
||||
<span class="track-count">100 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="genre-chart-type-card" data-chart-type="hype-picks" data-chart-endpoint="/api/beatport/homepage/hype-picks">
|
||||
<div class="chart-type-icon">⚡</div>
|
||||
<div class="chart-type-info">
|
||||
<h3>Hype Picks</h3>
|
||||
<p>Editor selected hype tracks</p>
|
||||
<span class="track-count">50 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -692,55 +735,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Staff Picks Sub-View -->
|
||||
<div class="beatport-sub-view" id="beatport-staff-picks-view">
|
||||
<div class="beatport-breadcrumb">
|
||||
<button class="breadcrumb-back">← Back to Categories</button>
|
||||
<span class="breadcrumb-path">Browse Charts > Staff Picks</span>
|
||||
</div>
|
||||
<div class="beatport-chart-list">
|
||||
<div class="beatport-chart-item" data-chart-type="staff-pick" data-chart-id="best-new-tracks">
|
||||
<div class="chart-icon">⭐</div>
|
||||
<div class="chart-info">
|
||||
<h3>Best New Tracks</h3>
|
||||
<p>Editor's picks of the week</p>
|
||||
<span class="track-count">20 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="staff-pick" data-chart-id="secret-weapons">
|
||||
<div class="chart-icon">🔫</div>
|
||||
<div class="chart-info">
|
||||
<h3>Secret Weapons</h3>
|
||||
<p>Underground gems for DJs</p>
|
||||
<span class="track-count">15 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="staff-pick" data-chart-id="closing-essentials">
|
||||
<div class="chart-icon">🌅</div>
|
||||
<div class="chart-info">
|
||||
<h3>Closing Essentials</h3>
|
||||
<p>Perfect tracks to end the night</p>
|
||||
<span class="track-count">12 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="staff-pick" data-chart-id="peak-time-driving">
|
||||
<div class="chart-icon">🔥</div>
|
||||
<div class="chart-info">
|
||||
<h3>Peak Time Driving</h3>
|
||||
<p>High-energy dancefloor destroyers</p>
|
||||
<span class="track-count">25 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="beatport-chart-item" data-chart-type="staff-pick" data-chart-id="underground-gems">
|
||||
<div class="chart-icon">💎</div>
|
||||
<div class="chart-info">
|
||||
<h3>Underground Gems</h3>
|
||||
<p>Hidden treasures from emerging artists</p>
|
||||
<span class="track-count">18 tracks</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -9733,14 +9733,18 @@ function initializeSyncPage() {
|
|||
});
|
||||
});
|
||||
|
||||
// Logic for Beatport category cards
|
||||
const beatportCategoryCards = document.querySelectorAll('.beatport-category-card');
|
||||
beatportCategoryCards.forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
const category = card.dataset.category;
|
||||
handleBeatportCategoryClick(category);
|
||||
// Logic for Homepage Genre Explorer card
|
||||
const genreExplorerCard = document.querySelector('[data-action="show-genres"]');
|
||||
if (genreExplorerCard) {
|
||||
genreExplorerCard.addEventListener('click', () => {
|
||||
console.log('🎵 Genre Explorer card clicked');
|
||||
showBeatportSubView('genres');
|
||||
loadBeatportGenres();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Setup homepage chart handlers (following genre page pattern to prevent duplicates)
|
||||
setupHomepageChartTypeHandlers();
|
||||
|
||||
// Logic for Beatport breadcrumb back buttons
|
||||
const beatportBackButtons = document.querySelectorAll('.breadcrumb-back');
|
||||
|
|
@ -10188,19 +10192,12 @@ async function clearBeatportPlaylists() {
|
|||
function handleBeatportCategoryClick(category) {
|
||||
console.log(`🎵 Beatport category clicked: ${category}`);
|
||||
|
||||
// Show the appropriate sub-view based on category
|
||||
// Only handle genres category now - homepage has direct chart buttons
|
||||
switch(category) {
|
||||
case 'top-charts':
|
||||
showBeatportSubView('top-charts');
|
||||
loadBeatportTopCharts(); // Load top charts dynamically
|
||||
break;
|
||||
case 'genres':
|
||||
showBeatportSubView('genres');
|
||||
loadBeatportGenres(); // Load genres dynamically
|
||||
break;
|
||||
case 'staff-picks':
|
||||
showBeatportSubView('staff-picks');
|
||||
break;
|
||||
default:
|
||||
showToast(`Unknown category: ${category}`, 'error');
|
||||
}
|
||||
|
|
@ -10369,159 +10366,148 @@ async function loadGenreImagesProgressively(genres) {
|
|||
console.log(`✅ Progressive image loading complete: ${imagesLoaded}/${genres.length} images loaded`);
|
||||
}
|
||||
|
||||
async function loadBeatportTopCharts() {
|
||||
console.log('🔥 Loading Beatport top charts dynamically...');
|
||||
function setupHomepageChartTypeHandlers() {
|
||||
console.log('🔧 Setting up homepage chart type handlers...');
|
||||
|
||||
const chartList = document.querySelector('#beatport-top-charts-view .beatport-chart-list');
|
||||
if (!chartList) {
|
||||
console.error('❌ Could not find chart list element');
|
||||
// Select all homepage chart type cards (following genre page pattern)
|
||||
const chartTypeCards = document.querySelectorAll('.homepage-main-charts-section .genre-chart-type-card[data-chart-type], .homepage-releases-section .genre-chart-type-card[data-chart-type], .homepage-hype-section .genre-chart-type-card[data-chart-type]');
|
||||
|
||||
chartTypeCards.forEach(card => {
|
||||
// Remove existing listeners by cloning (following genre page pattern)
|
||||
card.replaceWith(card.cloneNode(true));
|
||||
});
|
||||
|
||||
// Re-select after cloning to ensure clean event listeners (following genre page pattern)
|
||||
const newChartTypeCards = document.querySelectorAll('.homepage-main-charts-section .genre-chart-type-card[data-chart-type], .homepage-releases-section .genre-chart-type-card[data-chart-type], .homepage-hype-section .genre-chart-type-card[data-chart-type]');
|
||||
|
||||
newChartTypeCards.forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
const chartType = card.dataset.chartType;
|
||||
const chartEndpoint = card.dataset.chartEndpoint;
|
||||
const chartName = card.querySelector('.chart-type-info h3').textContent;
|
||||
console.log(`🔥 Homepage chart clicked: ${chartName} (${chartType})`);
|
||||
handleHomepageChartTypeClick(chartType, chartEndpoint, chartName);
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`✅ Setup ${newChartTypeCards.length} homepage chart handlers`);
|
||||
}
|
||||
|
||||
async function handleHomepageChartTypeClick(chartType, chartEndpoint, chartName) {
|
||||
console.log(`🔥 Homepage chart type clicked: ${chartType} (${chartName})`);
|
||||
|
||||
// Map chart types to API endpoints and create descriptive names (following genre page pattern)
|
||||
const chartTypeMap = {
|
||||
'top-10': {
|
||||
endpoint: `/api/beatport/top-100`, // Use top-100 endpoint and limit to 10
|
||||
name: `Beatport Top 10`,
|
||||
limit: 10
|
||||
},
|
||||
'top-100': {
|
||||
endpoint: `/api/beatport/top-100`,
|
||||
name: `Beatport Top 100`,
|
||||
limit: 100
|
||||
},
|
||||
'releases-top-10': {
|
||||
endpoint: `/api/beatport/homepage/releases-top-10`, // Placeholder for future
|
||||
name: `Top 10 Releases`,
|
||||
limit: 10
|
||||
},
|
||||
'releases-top-100': {
|
||||
endpoint: `/api/beatport/top-100-releases`,
|
||||
name: `Top 100 Releases`,
|
||||
limit: 100
|
||||
},
|
||||
'latest-releases': {
|
||||
endpoint: `/api/beatport/homepage/latest-releases`, // Placeholder for future
|
||||
name: `Latest Releases`,
|
||||
limit: 50
|
||||
},
|
||||
'hype-top-10': {
|
||||
endpoint: `/api/beatport/hype-top-100`, // Use hype-100 endpoint and limit to 10
|
||||
name: `Hype Top 10`,
|
||||
limit: 10
|
||||
},
|
||||
'hype-top-100': {
|
||||
endpoint: `/api/beatport/hype-top-100`,
|
||||
name: `Hype Top 100`,
|
||||
limit: 100
|
||||
},
|
||||
'hype-picks': {
|
||||
endpoint: `/api/beatport/homepage/hype-picks`, // Placeholder for future
|
||||
name: `Hype Picks`,
|
||||
limit: 50
|
||||
}
|
||||
};
|
||||
|
||||
const chartConfig = chartTypeMap[chartType];
|
||||
if (!chartConfig) {
|
||||
console.error(`❌ Unknown homepage chart type: ${chartType}`);
|
||||
showToast(`Unknown chart type: ${chartType}`, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
chartList.innerHTML = `
|
||||
<div class="chart-loading-placeholder">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>🔥 Discovering current Beatport top charts...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
try {
|
||||
// Define the top charts we want to show (based on our working endpoints)
|
||||
const topCharts = [
|
||||
{
|
||||
id: 'beatport-top-100',
|
||||
name: 'Beatport Top 100',
|
||||
description: 'The hottest electronic tracks right now',
|
||||
icon: '🏆',
|
||||
endpoint: '/api/beatport/top-100',
|
||||
trackCount: '100 tracks'
|
||||
},
|
||||
{
|
||||
id: 'top-100-releases',
|
||||
name: 'Top 100 New Releases',
|
||||
description: 'Newest and most popular releases on Beatport',
|
||||
icon: '📀',
|
||||
endpoint: '/api/beatport/top-100-releases',
|
||||
trackCount: '100 tracks'
|
||||
},
|
||||
{
|
||||
id: 'hype-top-100',
|
||||
name: 'Hype Top 100',
|
||||
description: 'Trending tracks gaining momentum',
|
||||
icon: '🚀',
|
||||
endpoint: '/api/beatport/hype-top-100',
|
||||
trackCount: '100 tracks'
|
||||
}
|
||||
];
|
||||
|
||||
// Generate chart cards dynamically
|
||||
const chartCardsHTML = topCharts.map(chart => `
|
||||
<div class="beatport-chart-item"
|
||||
data-chart-type="${chart.id}"
|
||||
data-chart-id="${chart.id}"
|
||||
data-chart-name="${chart.name}"
|
||||
data-chart-endpoint="${chart.endpoint}">
|
||||
<div class="chart-icon">${chart.icon}</div>
|
||||
<div class="chart-info">
|
||||
<h3>${chart.name}</h3>
|
||||
<p>${chart.description}</p>
|
||||
<span class="track-count">${chart.trackCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
chartList.innerHTML = chartCardsHTML;
|
||||
|
||||
// Add click handlers to dynamically created chart items
|
||||
const chartItems = chartList.querySelectorAll('.beatport-chart-item');
|
||||
chartItems.forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
const chartType = item.dataset.chartType;
|
||||
const chartId = item.dataset.chartId;
|
||||
const chartName = item.dataset.chartName;
|
||||
const chartEndpoint = item.dataset.chartEndpoint;
|
||||
handleBeatportTopChartClick(chartType, chartId, chartName, chartEndpoint);
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`✅ Loaded ${topCharts.length} Beatport top charts dynamically`);
|
||||
showToast(`Loaded ${topCharts.length} top charts`, 'success');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error loading Beatport top charts:', error);
|
||||
chartList.innerHTML = `
|
||||
<div class="chart-error-placeholder">
|
||||
<p>❌ Failed to load top charts: ${error.message}</p>
|
||||
<button onclick="loadBeatportTopCharts()" class="refresh-charts-btn">🔄 Retry</button>
|
||||
</div>
|
||||
`;
|
||||
showToast(`Error loading Beatport top charts: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleBeatportTopChartClick(chartType, chartId, chartName, chartEndpoint) {
|
||||
console.log(`🔥 Beatport top chart clicked: ${chartName} - CREATING PLAYLIST CARD`);
|
||||
|
||||
try {
|
||||
// Check if we already have a card for this chart
|
||||
// Check if we already have a card for this specific chart type (following genre page pattern)
|
||||
const existingState = Object.values(beatportChartStates).find(state =>
|
||||
state.chart && state.chart.name === chartName && state.chart.chart_type === chartType
|
||||
state.chart && state.chart.name === chartConfig.name && state.chart.chart_type === `homepage_${chartType}`
|
||||
);
|
||||
|
||||
if (existingState) {
|
||||
console.log(`🔄 Found existing Beatport card for ${chartName}, opening existing modal`);
|
||||
console.log(`🔄 Found existing Beatport card for ${chartConfig.name}, opening existing modal`);
|
||||
handleBeatportCardClick(existingState.chart.hash);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, create a chart hash for state management
|
||||
const chartHash = `${chartType}_${chartId}_${Date.now()}`;
|
||||
// Create a chart hash for state management (following genre page pattern)
|
||||
const chartHash = `homepage_${chartType}_${Date.now()}`;
|
||||
|
||||
showToast(`Loading ${chartName}...`, 'info');
|
||||
showToast(`Loading ${chartConfig.name}...`, 'info');
|
||||
|
||||
// Fetch tracks from the chart endpoint
|
||||
const response = await fetch(`${chartEndpoint}?limit=100`);
|
||||
// Fetch tracks from the specific endpoint (following genre page pattern)
|
||||
const response = await fetch(`${chartConfig.endpoint}?limit=${chartConfig.limit}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch ${chartName}: ${response.status}`);
|
||||
throw new Error(`Failed to fetch ${chartConfig.name}: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (!data.success || !data.tracks || data.tracks.length === 0) {
|
||||
throw new Error(`No tracks found in ${chartName}`);
|
||||
throw new Error(`No tracks found in ${chartConfig.name}`);
|
||||
}
|
||||
|
||||
// Create chart data object for playlist card
|
||||
// Create chart data object for playlist card (following genre page pattern)
|
||||
const chartData = {
|
||||
hash: chartHash,
|
||||
name: chartName,
|
||||
chart_type: chartType,
|
||||
name: chartConfig.name,
|
||||
chart_type: `homepage_${chartType}`,
|
||||
track_count: data.tracks.length,
|
||||
tracks: data.tracks.map(track => ({
|
||||
name: track.title || 'Unknown Title',
|
||||
artists: [track.artist || 'Unknown Artist'],
|
||||
album: chartName,
|
||||
album: chartConfig.name,
|
||||
duration_ms: 0,
|
||||
external_urls: { beatport: track.url || '' },
|
||||
source: 'beatport'
|
||||
}))
|
||||
};
|
||||
|
||||
// Add card to container (in background, like YouTube does)
|
||||
console.log(`🃏 Creating Beatport playlist card for: ${chartName}`);
|
||||
// Add card to container (in background, like YouTube does - following genre page pattern)
|
||||
console.log(`🃏 Creating Beatport playlist card for: ${chartConfig.name}`);
|
||||
addBeatportCardToContainer(chartData);
|
||||
|
||||
// Automatically open discovery modal (like when you click a YouTube or Tidal card in fresh state)
|
||||
// Automatically open discovery modal (like when you click a YouTube or Tidal card in fresh state - following genre page pattern)
|
||||
handleBeatportCardClick(chartHash);
|
||||
|
||||
console.log(`✅ Created Beatport card and opened discovery modal for ${chartName}`);
|
||||
console.log(`✅ Created Beatport card and opened discovery modal for ${chartConfig.name}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error loading ${chartName}:`, error);
|
||||
showToast(`Error loading ${chartName}: ${error.message}`, 'error');
|
||||
console.error(`❌ Error loading ${chartConfig.name}:`, error);
|
||||
showToast(`Error loading ${chartConfig.name}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function openBeatportDiscoveryModal(chartHash, chartData) {
|
||||
console.log(`🎵 Opening Beatport discovery modal (reusing YouTube modal): ${chartData.name}`);
|
||||
|
||||
|
|
|
|||
|
|
@ -4893,7 +4893,11 @@ body {
|
|||
.genre-main-charts-section,
|
||||
.genre-releases-section,
|
||||
.genre-editorial-section,
|
||||
.genre-new-charts-section {
|
||||
.genre-new-charts-section,
|
||||
.homepage-genre-section,
|
||||
.homepage-main-charts-section,
|
||||
.homepage-releases-section,
|
||||
.homepage-hype-section {
|
||||
margin-bottom: 40px;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg,
|
||||
|
|
@ -5065,6 +5069,52 @@ body {
|
|||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* Empty Section Placeholder */
|
||||
.empty-section-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
padding: 40px 20px;
|
||||
background: linear-gradient(135deg,
|
||||
rgba(30, 30, 30, 0.5) 0%,
|
||||
rgba(20, 20, 20, 0.7) 100%);
|
||||
border-radius: 12px;
|
||||
border: 2px dashed rgba(255, 255, 255, 0.15);
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 120px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-section-placeholder:hover {
|
||||
opacity: 1;
|
||||
border-color: rgba(255, 255, 255, 0.25);
|
||||
background: linear-gradient(135deg,
|
||||
rgba(35, 35, 35, 0.6) 0%,
|
||||
rgba(25, 25, 25, 0.8) 100%);
|
||||
}
|
||||
|
||||
.empty-section-icon {
|
||||
font-size: 48px;
|
||||
opacity: 0.6;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.empty-section-text h4 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.empty-section-text p {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.expand-indicator {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
|
@ -5520,7 +5570,11 @@ body {
|
|||
.genre-main-charts-section,
|
||||
.genre-releases-section,
|
||||
.genre-editorial-section,
|
||||
.genre-new-charts-section {
|
||||
.genre-new-charts-section,
|
||||
.homepage-genre-section,
|
||||
.homepage-main-charts-section,
|
||||
.homepage-releases-section,
|
||||
.homepage-hype-section {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue