Add Beatport Top 100 button to genre page
Introduces a 'Beatport Top 100' button to each genre page, allowing users to fetch and view the top 100 tracks for a selected genre. Includes new event handling logic in script.js and corresponding styles in style.css for the button and its container.
This commit is contained in:
parent
fd92deb5c8
commit
fcd48793e0
2 changed files with 129 additions and 1 deletions
|
|
@ -21301,6 +21301,14 @@ function showGenrePageView(genreSlug, genreId, genreName) {
|
||||||
<p class="genre-loading-text">🎠 Loading hero releases...</p>
|
<p class="genre-loading-text">🎠 Loading hero releases...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="genre-nav-buttons-section">
|
||||||
|
<div class="genre-nav-buttons-container">
|
||||||
|
<button class="beatport-nav-button" id="genre-top100-btn">
|
||||||
|
<span class="beatport-nav-icon top100-icon"></span>
|
||||||
|
<span class="beatport-nav-text">Beatport Top 100</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
modal.querySelector('.genre-browser-modal-content').appendChild(genrePageContent);
|
modal.querySelector('.genre-browser-modal-content').appendChild(genrePageContent);
|
||||||
|
|
@ -21310,6 +21318,14 @@ function showGenrePageView(genreSlug, genreId, genreName) {
|
||||||
if (backButton) {
|
if (backButton) {
|
||||||
backButton.addEventListener('click', showGenreListView);
|
backButton.addEventListener('click', showGenreListView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add genre top 100 button listener
|
||||||
|
const genreTop100Button = genrePageContent.querySelector('#genre-top100-btn');
|
||||||
|
if (genreTop100Button) {
|
||||||
|
genreTop100Button.addEventListener('click', () => {
|
||||||
|
handleGenreTop100Click(genreSlug, genreId, genreName);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update title and show genre page
|
// Update title and show genre page
|
||||||
|
|
@ -21663,6 +21679,95 @@ function startGenreHeroSliderAutoPlay() {
|
||||||
console.log(`▶️ Started auto-play for genre hero slider (${window.genreHeroSliderState.totalSlides} slides)`);
|
console.log(`▶️ Started auto-play for genre hero slider (${window.genreHeroSliderState.totalSlides} slides)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle genre-specific Top 100 button click - create discovery process for genre top 100 tracks
|
||||||
|
*/
|
||||||
|
async function handleGenreTop100Click(genreSlug, genreId, genreName) {
|
||||||
|
console.log(`💯 Genre Top 100 button clicked for ${genreName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create unique identifiers for this chart
|
||||||
|
const chartHash = `${genreSlug}_top100_${Date.now()}`;
|
||||||
|
const chartName = `${genreName} Top 100`;
|
||||||
|
|
||||||
|
showToast(`Loading ${genreName} Top 100...`, 'info');
|
||||||
|
showLoadingOverlay(`Getting ${genreName} Top 100 tracks...`);
|
||||||
|
|
||||||
|
// Check if we already have a card for this genre's Top 100
|
||||||
|
const existingState = Object.values(beatportChartStates).find(state =>
|
||||||
|
state.chart &&
|
||||||
|
state.chart.name === chartName &&
|
||||||
|
state.chart.chart_type === 'genre_top100'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingState) {
|
||||||
|
console.log(`🔄 Found existing ${genreName} Top 100 card, opening existing modal`);
|
||||||
|
hideLoadingOverlay();
|
||||||
|
handleBeatportCardClick(existingState.chart.hash);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the genre top 100 URL: genre URL + /top-100
|
||||||
|
const genreTop100Url = `https://www.beatport.com/genre/${genreSlug}/${genreId}/top-100`;
|
||||||
|
console.log(`💯 Fetching tracks from ${genreTop100Url}`);
|
||||||
|
|
||||||
|
// Get track data from genre top 100 page
|
||||||
|
const response = await fetch('/api/beatport/scrape-releases', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
release_urls: [genreTop100Url],
|
||||||
|
source_name: chartName
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!data.success || !data.tracks || data.tracks.length === 0) {
|
||||||
|
throw new Error(`No tracks found in ${genreName} Top 100`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Successfully fetched ${data.tracks.length} tracks from ${genreName} Top 100`);
|
||||||
|
|
||||||
|
// Transform to standard chart format (following the exact pattern)
|
||||||
|
const chartData = {
|
||||||
|
hash: chartHash,
|
||||||
|
name: chartName,
|
||||||
|
chart_type: 'genre_top100',
|
||||||
|
track_count: data.tracks.length,
|
||||||
|
tracks: data.tracks.map(track => ({
|
||||||
|
name: cleanTrackText(track.title || 'Unknown Title'),
|
||||||
|
artists: [cleanTrackText(track.artist || 'Unknown Artist')],
|
||||||
|
album: chartName,
|
||||||
|
duration_ms: 0,
|
||||||
|
external_urls: { beatport: track.url || '' },
|
||||||
|
source: 'beatport',
|
||||||
|
// Include genre metadata
|
||||||
|
genre_slug: genreSlug,
|
||||||
|
genre_id: genreId,
|
||||||
|
genre_name: genreName,
|
||||||
|
position: track.position || track.rank
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create Beatport playlist card (following the exact pattern)
|
||||||
|
addBeatportCardToContainer(chartData);
|
||||||
|
|
||||||
|
// Automatically open discovery modal (following the exact pattern)
|
||||||
|
hideLoadingOverlay();
|
||||||
|
handleBeatportCardClick(chartHash);
|
||||||
|
|
||||||
|
console.log(`✅ Created ${genreName} Top 100 card and opened discovery modal`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Error handling ${genreName} Top 100 click:`, error);
|
||||||
|
hideLoadingOverlay();
|
||||||
|
showToast(`Error loading ${genreName} Top 100: ${error.message}`, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the Genre Browser Modal when the page loads
|
// Initialize the Genre Browser Modal when the page loads
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
initializeGenreBrowserModal();
|
initializeGenreBrowserModal();
|
||||||
|
|
|
||||||
|
|
@ -14988,7 +14988,7 @@ body {
|
||||||
|
|
||||||
.genre-hero-slider-container {
|
.genre-hero-slider-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 80px);
|
height: fit-content;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -15058,6 +15058,24 @@ body {
|
||||||
border-color: rgba(255, 255, 255, 0.25);
|
border-color: rgba(255, 255, 255, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === GENRE NAV BUTTONS SECTION === */
|
||||||
|
|
||||||
|
.genre-nav-buttons-section {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.genre-nav-buttons-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The button styles are already defined in the main .beatport-nav-button class */
|
||||||
|
/* This ensures the genre page button looks identical to the main page buttons */
|
||||||
|
|
||||||
/* Responsive adjustments for genre page */
|
/* Responsive adjustments for genre page */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.genre-page-header {
|
.genre-page-header {
|
||||||
|
|
@ -15069,4 +15087,9 @@ body {
|
||||||
.genre-page-title {
|
.genre-page-title {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.genre-nav-buttons-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue