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:
Broque Thomas 2025-10-01 17:59:38 -07:00
parent fd92deb5c8
commit fcd48793e0
2 changed files with 129 additions and 1 deletions

View file

@ -21301,6 +21301,14 @@ function showGenrePageView(genreSlug, genreId, genreName) {
<p class="genre-loading-text">🎠 Loading hero releases...</p>
</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);
@ -21310,6 +21318,14 @@ function showGenrePageView(genreSlug, genreId, genreName) {
if (backButton) {
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
@ -21663,6 +21679,95 @@ function startGenreHeroSliderAutoPlay() {
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
document.addEventListener('DOMContentLoaded', () => {
initializeGenreBrowserModal();

View file

@ -14988,7 +14988,7 @@ body {
.genre-hero-slider-container {
width: 100%;
height: calc(100% - 80px);
height: fit-content;
overflow-y: auto;
}
@ -15058,6 +15058,24 @@ body {
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 */
@media (max-width: 768px) {
.genre-page-header {
@ -15069,4 +15087,9 @@ body {
.genre-page-title {
font-size: 20px;
}
.genre-nav-buttons-section {
margin-top: 20px;
padding: 15px 0;
}
}