Created
June 17, 2025 20:54
-
-
Save jacqueswww/8890896c97070ea6034f2007a466900c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>The Howl on the Airwaves: An Interactive Exploration of "Eve of Destruction"</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<link rel="preconnect" href="https://fonts.googleapis.com"> | |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700;900&family=Roboto:wght@400;500&display=swap" rel="stylesheet"> | |
<!-- Chosen Palette: Vintage Protest --> | |
<!-- Application Structure Plan: A thematic, narrative-driven single-page application. The user scrolls through a story that begins with the historical context (The Cauldron), dives deep into the song's components (Anatomy of a Howl), explores its controversial impact (The Hit & The Heresy), and concludes with an interactive music discovery tool (Echoes of Destruction). This structure was chosen to transform the linear report into an engaging, exploratory journey, allowing users to interact with the key data points (lyrics, historical facts, song recommendations) directly, rather than just reading them. The flow is designed to build understanding layer by layer. --> | |
<!-- Visualization & Content Choices: | |
- Historical Context: Report Info -> 1965 Crises (Vietnam, Cold War, Civil Rights). Goal -> Inform/Compare. Viz/Presentation -> Interactive three-column card layout using HTML/Tailwind. Interaction -> Hover effects reveal key stats. Justification -> Makes dense historical text scannable and highlights the simultaneous nature of the crises. Library/Method -> HTML/CSS. | |
- Lyrical Analysis: Report Info -> Lyrical analysis table. Goal -> Organize/Inform. Viz/Presentation -> Interactive lyric explorer. Interaction -> Clicking a highlighted lyric reveals its meaning in a modal window. Justification -> Far more engaging than a static table; connects the words directly to their context. Library/Method -> HTML/JS. | |
- Chart Performance: Report Info -> Reached #1 on Billboard, but was banned. Goal -> Compare/Inform. Viz/Presentation -> Line chart from Chart.js showing its rapid climb. Interaction -> Tooltips and annotations on the chart. Justification -> Visually represents the central paradox of the song's success vs. its controversy. Library/Method -> Chart.js. | |
- Song Recommendations: Report Info -> Curated list of songs. Goal -> Organize/Inform. Viz/Presentation -> An interactive, filterable grid of song cards. Interaction -> Users click filter buttons to sort songs by theme; clicking a card reveals details and a YouTube link. Justification -> Turns a static list into a functional music discovery tool, directly addressing the user's initial request. Library/Method -> HTML/JS. | |
--> | |
<!-- CONFIRMATION: NO SVG graphics used. NO Mermaid JS used. --> | |
<style> | |
body { | |
font-family: 'Roboto', sans-serif; | |
background-color: #FDFBF8; /* Warm off-white */ | |
color: #312E2B; /* Dark Brown/Charcoal */ | |
} | |
h1, h2, h3 { | |
font-family: 'Roboto Slab', serif; | |
font-weight: 900; | |
letter-spacing: -0.025em; | |
} | |
.nav-link { | |
transition: color 0.3s, border-color 0.3s; | |
border-bottom: 2px solid transparent; | |
} | |
.nav-link:hover, .nav-link.active { | |
color: #B9452C; /* Muted Red Accent */ | |
border-bottom-color: #B9452C; | |
} | |
.lyric-highlight { | |
background-color: rgba(217, 189, 165, 0.3); /* Muted Olive/Tan highlight */ | |
cursor: pointer; | |
transition: background-color 0.3s; | |
} | |
.lyric-highlight:hover { | |
background-color: rgba(217, 189, 165, 0.6); | |
} | |
.card-flip { | |
perspective: 1000px; | |
} | |
.card-flip-inner { | |
position: relative; | |
width: 100%; | |
height: 100%; | |
transition: transform 0.6s; | |
transform-style: preserve-3d; | |
} | |
.card-flip.flipped .card-flip-inner { | |
transform: rotateY(180deg); | |
} | |
.card-face { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
-webkit-backface-visibility: hidden; | |
backface-visibility: hidden; | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
} | |
.card-back { | |
transform: rotateY(180deg); | |
} | |
.chart-container { | |
position: relative; | |
width: 100%; | |
max-width: 800px; | |
margin-left: auto; | |
margin-right: auto; | |
height: 400px; | |
max-height: 50vh; | |
} | |
</style> | |
</head> | |
<body class="antialiased"> | |
<!-- Header & Navigation --> | |
<header class="bg-opacity-80 backdrop-blur-md sticky top-0 z-40 w-full border-b border-gray-200"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="flex items-center justify-between h-16"> | |
<div class="flex items-center"> | |
<h1 class="text-xl font-black text-[#B9452C]">Eve of Destruction</h1> | |
</div> | |
<nav class="hidden md:flex space-x-8"> | |
<a href="#introduction" class="nav-link text-sm font-medium">Introduction</a> | |
<a href="#cauldron" class="nav-link text-sm font-medium">The Cauldron of 1965</a> | |
<a href="#anatomy" class="nav-link text-sm font-medium">Anatomy of a Howl</a> | |
<a href="#impact" class="nav-link text-sm font-medium">Impact</a> | |
<a href="#echoes" class="nav-link text-sm font-medium">Echoes</a> | |
</nav> | |
</div> | |
</div> | |
</header> | |
<main> | |
<!-- Section 1: Introduction --> | |
<section id="introduction" class="py-20 sm:py-24"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8 text-center"> | |
<p class="text-base font-semibold text-[#B9452C]">A Howl on the Airwaves</p> | |
<h1 class="mt-2 text-4xl sm:text-5xl lg:text-6xl font-black tracking-tight">Deconstructing "Eve of Destruction"</h1> | |
<p class="mt-6 max-w-3xl mx-auto text-lg text-gray-600">In the summer of 1965, a raw, desperate warning crashed through the pop charts. This is an interactive exploration of that song: a perfect, volatile storm of ripped-from-the-headlines lyrics, an accidentally authentic performance, and a historical moment so tense that its bleak prophecy felt terrifyingly real. Journey through the song's context, construction, and enduring legacy.</p> | |
</div> | |
</section> | |
<!-- Section 2: The Cauldron of 1965 --> | |
<section id="cauldron" class="py-20 sm:py-24 bg-gray-50"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="text-center"> | |
<h2 class="text-3xl sm:text-4xl font-black">A World on the Brink</h2> | |
<p class="mt-4 max-w-2xl mx-auto text-lg text-gray-600">To understand the song, you must understand the world that created it. 1965 was a year of violent escalation on multiple fronts. This section explores the three interwoven crises—war, nuclear fear, and the struggle for civil rights—that formed the chaotic backdrop for the song's creation. The lyrics didn't invent the anxiety; they simply reported it.</p> | |
</div> | |
<div class="mt-16 grid gap-8 md:grid-cols-3"> | |
<!-- Vietnam War Card --> | |
<div class="bg-white p-8 rounded-lg shadow-md border border-gray-200"> | |
<div class="text-4xl">💣</div> | |
<h3 class="mt-4 text-2xl font-bold">The Shadow of Vietnam</h3> | |
<p class="mt-2 text-gray-600">The war escalated dramatically in 1965, transforming from a distant conflict into a full-scale American war. Operation Rolling Thunder began, and ground troops were committed for the first time.</p> | |
<div class="mt-6 pt-4 border-t border-gray-200"> | |
<p class="text-sm text-gray-500">U.S. Troops in Vietnam (1965)</p> | |
<p class="text-3xl font-bold">23,000 ➔ 200,000</p> | |
</div> | |
</div> | |
<!-- Cold War Card --> | |
<div class="bg-white p-8 rounded-lg shadow-md border border-gray-200"> | |
<div class="text-4xl">☢️</div> | |
<h3 class="mt-4 text-2xl font-bold">The Cold War's Nuclear Dread</h3> | |
<p class="mt-2 text-gray-600">The existential threat of nuclear annihilation was a daily reality. With the Cuban Missile Crisis a fresh memory, the fear of "the button" being pushed was not hyperbole; it was the apocalyptic heart of the era.</p> | |
<div class="mt-6 pt-4 border-t border-gray-200"> | |
<p class="text-sm text-gray-500">The Ultimate Fear</p> | |
<p class="text-2xl font-bold">Mutually Assured Destruction</p> | |
</div> | |
</div> | |
<!-- Civil Rights Card --> | |
<div class="bg-white p-8 rounded-lg shadow-md border border-gray-200"> | |
<div class="text-4xl">✊🏾</div> | |
<h3 class="mt-4 text-2xl font-bold">The Fire at Home</h3> | |
<p class="mt-2 text-gray-600">1965 was a watershed year for the Civil Rights Movement. The brutal "Bloody Sunday" attack on marchers in Selma, Alabama, shocked the world and exposed the deep-seated hatred the movement was fighting against.</p> | |
<div class="mt-6 pt-4 border-t border-gray-200"> | |
<p class="text-sm text-gray-500">Pivotal Event</p> | |
<p class="text-2xl font-bold">Selma to Montgomery Marches</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</section> | |
<!-- Section 3: Anatomy of a Howl --> | |
<section id="anatomy" class="py-20 sm:py-24"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="text-center"> | |
<h2 class="text-3xl sm:text-4xl font-black">Anatomy of a Howl</h2> | |
<p class="mt-4 max-w-2xl mx-auto text-lg text-gray-600">The song's genius lies in its construction. It marries the "laundry-list" lyrical style of folk protest with the electric urgency of rock, all delivered with a raw, desperate vocal that was never meant to be released. Explore the key elements below. Click on the highlighted lyrics to see their direct connection to the events of 1965.</p> | |
</div> | |
<div class="mt-16 grid lg:grid-cols-2 gap-12 items-start"> | |
<div class="bg-gray-50 p-6 sm:p-8 rounded-lg border border-gray-200"> | |
<h3 class="text-2xl font-bold mb-4">Lyrical Litany</h3> | |
<div class="text-base sm:text-lg leading-relaxed space-y-2 text-gray-700"> | |
<p>The eastern world, it is explodin',</p> | |
<p>Violence flarin', bullets loadin'.</p> | |
<p><span class="lyric-highlight rounded px-1" data-lyric="votin">You're old enough to kill, but not for votin',</span></p> | |
<p>You don't believe in war, but what's that gun you're totin'?</p> | |
<p>And even the Jordan River has bodies floatin'.</p> | |
<p>But you tell me over and over and over again, my friend,</p> | |
<p>Ah, you don't believe we're on the eve of destruction.</p> | |
<p>Don't you understand what I'm tryin' to say?</p> | |
<p>And can't you feel the fears I'm feelin' today?</p> | |
<p><span class="lyric-highlight rounded px-1" data-lyric="button">If the button is pushed, there's no runnin' away,</span></p> | |
<p>There'll be no one to save with the world in a grave.</p> | |
<p><span class="lyric-highlight rounded px-1" data-lyric="integration">Marches alone can't bring integration, when human respect is disintegratin',</span></p> | |
<p>This whole crazy world is just too frustratin'.</p> | |
<p><span class="lyric-highlight rounded px-1" data-lyric="selma">Think of all the hate there is in Red China, then take a look around to Selma, Alabama.</span></p> | |
<p>Ah, you may leave here for four days in space,</p> | |
<p><span class="lyric-highlight rounded px-1" data-lyric="space">But when you return, it's the same old place.</span></p> | |
<p>The poundin' of the drums, the pride and disgrace...</p> | |
</div> | |
</div> | |
<div class="space-y-8"> | |
<div> | |
<h3 class="text-xl font-bold">Folk-Rock Fury</h3> | |
<p class="mt-2 text-gray-600">Musically, the song was a perfect example of the new folk-rock sound, blending Bob Dylan's lyrical substance with a driving rock beat. The backing track was ironically played by The Wrecking Crew, L.A.'s top session musicians, giving its raw message a powerful, radio-ready momentum.</p> | |
</div> | |
<div> | |
<h3 class="text-xl font-bold">Accidental Authenticity</h3> | |
<p class="mt-2 text-gray-600">Barry McGuire's raw, gravelly vocal is the song's soul. The iconic version was a one-take demo recorded from a crumpled lyric sheet, never intended for release. Its imperfections—the strain, the audible hesitation—are the genuine sound of a man wrestling with an urgent, frightening message, and its honesty connected viscerally with a generation that felt the same way.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</section> | |
<!-- Section 4: The Hit and the Heresy --> | |
<section id="impact" class="py-20 sm:py-24 bg-gray-50"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="text-center"> | |
<h2 class="text-3xl sm:text-4xl font-black">The Hit and the Heresy</h2> | |
<p class="mt-4 max-w-2xl mx-auto text-lg text-gray-600">The song became a cultural flashpoint. It was so controversial it was banned by radio stations across the country, yet so resonant it shot to #1 on the Billboard charts. This paradox fueled its power, creating a "forbidden fruit" effect that made it a must-hear anthem for a generation questioning authority.</p> | |
</div> | |
<div class="mt-16"> | |
<div class="chart-container"> | |
<canvas id="billboardChart"></canvas> | |
</div> | |
</div> | |
<div class="mt-12 text-center p-6 bg-white rounded-lg shadow-md border border-gray-200 max-w-3xl mx-auto"> | |
<h3 class="text-2xl font-bold">The Dawn of Correction</h3> | |
<p class="mt-2 text-gray-600">The song's impact was so great it spawned a direct rebuttal. A group called The Spokesmen released "The Dawn of Correction," a point-by-point refutation of the song's pessimism, defending the establishment and praising the fight against communism. This musical dialogue highlights how "Eve of Destruction" forced a national conversation and drew a clear line in the sand.</p> | |
</div> | |
</div> | |
</section> | |
<!-- Section 5: Echoes of Destruction --> | |
<section id="echoes" class="py-20 sm:py-24"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="text-center"> | |
<h2 class="text-3xl sm:text-4xl font-black">Echoes of Destruction</h2> | |
<p class="mt-4 max-w-2xl mx-auto text-lg text-gray-600">"Eve of Destruction" created ripples that can still be felt in music today. This curated guide explores songs that share its spirit of protest, its cry against injustice, its apocalyptic dread, or its raw, unfiltered emotional power. Filter the collection by theme to discover your next obsession.</p> | |
</div> | |
<div id="filter-buttons" class="mt-12 flex flex-wrap justify-center gap-2"> | |
<!-- Filter buttons will be injected here --> | |
</div> | |
<div id="song-grid" class="mt-8 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> | |
<!-- Song cards will be injected here --> | |
</div> | |
</div> | |
</section> | |
</main> | |
<!-- Modal for Lyric Details --> | |
<div id="lyric-modal" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden items-center justify-center p-4"> | |
<div class="bg-white rounded-lg shadow-xl max-w-lg w-full p-6 relative"> | |
<button id="modal-close-btn" class="absolute top-4 right-4 text-gray-400 hover:text-gray-800">×</button> | |
<h3 id="modal-title" class="text-2xl font-bold mb-2"></h3> | |
<p id="modal-text" class="text-gray-700"></p> | |
</div> | |
</div> | |
<footer class="bg-gray-800 text-white py-8"> | |
<div class="container mx-auto px-4 sm:px-6 lg:px-8 text-center"> | |
<p>An interactive report created from a deep analysis of a timeless protest song.</p> | |
</div> | |
</footer> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
const lyricData = { | |
votin: { | |
title: "Old Enough to Kill, Not to Vote", | |
text: "The military draft age was 18, but the national voting age was 21. This was the central, infuriating hypocrisy for young Americans. The lyric became a rallying cry for the 26th Amendment, which eventually lowered the voting age in 1971." | |
}, | |
button: { | |
title: "The Nuclear Button", | |
text: "This lyric captures the ultimate existential dread of the Cold War's Atomic Age. The 1962 Cuban Missile Crisis was a fresh, terrifying memory, and the fear of mutually assured destruction transcended all other political issues." | |
}, | |
integration: { | |
title: "Limits of Protest", | |
text: "A pessimistic but realistic take on the Civil Rights Movement's struggle. Despite legislative efforts and peaceful protests like the Selma marches, this line questions the efficacy of protest in the face of deep-seated, systemic hatred." | |
}, | |
selma: { | |
title: "Hypocrisy at Home", | |
text: "This is the song's most radical political statement. It juxtaposes the official anti-communist rhetoric about 'Red China' with the racist violence seen in Selma, Alabama, exposing the hypocrisy of the U.S. government's moral posturing on the world stage." | |
}, | |
space: { | |
title: "Triumphalism vs. Reality", | |
text: "A direct reference to the Gemini 4 space mission in June 1965. The lyric critiques technological progress as a distraction from festering social problems, arguing that achievements in space are meaningless if society itself is decaying." | |
} | |
}; | |
const songData = [ | |
{ category: "The Pantheon of '60s Protest", title: "Masters of War", artist: "Bob Dylan", year: 1963, reason: "The thematic precursor to 'Eve.' A venomous, direct address to the war profiteers. While 'Eve' is a frantic cry, this is a cold, calculated curse.", youtubeUrl: "https://www.youtube.com/watch?v=JEmI_e4iaOk" }, | |
{ category: "The Pantheon of '60s Protest", title: "I Ain't Marching Anymore", artist: "Phil Ochs", year: 1965, reason: "Released the same year as 'Eve,' this is the ultimate statement of personal refusal to participate in war. A powerful folk anthem.", youtubeUrl: "https://www.youtube.com/watch?v=uRU_ruqnR6Q" }, | |
{ category: "The Pantheon of '60s Protest", title: "For What It's Worth", artist: "Buffalo Springfield", year: 1966, reason: "Captures the tense, paranoid atmosphere of the era. Less of a direct protest and more of an observational snapshot of a society fracturing.", youtubeUrl: "https://www.youtube.com/watch?v=gp5JCrSXgpe" }, | |
{ category: "The Pantheon of '60s Protest", title: "Fortunate Son", artist: "Creedence Clearwater Revival", year: 1969, reason: "A blistering rock takedown of the privileged elite who send the poor to fight their wars. Shares 'Eve's' rage at hypocrisy.", youtubeUrl: "https://www.youtube.com/watch?v=40JmEj0_aVM" }, | |
{ category: "Voices Against Injustice", title: "Mississippi Goddam", artist: "Nina Simone", year: 1964, reason: "The rawest, most furious musical response to Civil Rights violence. The emotional counterpart to 'Eve's' reference to Selma.", youtubeUrl: "https://www.youtube.com/watch?v=LJ25-U3jNWM" }, | |
{ category: "Voices Against Injustice", title: "A Change Is Gonna Come", artist: "Sam Cooke", year: 1964, reason: "Where Simone is furious, Cooke is weary but profoundly hopeful. An anthem born of pain that became a cornerstone of the movement.", youtubeUrl: "https://www.youtube.com/watch?v=wEBlaMOmKV4" }, | |
{ category: "Voices Against Injustice", title: "Strange Fruit", artist: "Billie Holiday", year: 1939, reason: "The foundational text of American musical protest. Its haunting, horrifying imagery of lynching laid the groundwork for all that followed.", youtubeUrl: "https://www.youtube.com/watch?v=Web007rzSOI" }, | |
{ category: "The Apocalypse Playlist", title: "A Hard Rain's A-Gonna Fall", artist: "Bob Dylan", year: 1963, reason: "A surreal, poetic vision of a world poisoned by lies and violence. While 'Eve' is a news report, 'Hard Rain' is a fever dream.", youtubeUrl: "https://www.youtube.com/watch?v=T5al0HmR4to" }, | |
{ category: "The Apocalypse Playlist", title: "Gimme Shelter", artist: "The Rolling Stones", year: 1969, reason: "The sound of the '60s dream dying. Its chaotic, menacing energy perfectly captures the sense of impending doom 'Eve' prophesied.", youtubeUrl: "https://www.youtube.com/watch?v=RbmS3tQJ7Os" }, | |
{ category: "The Apocalypse Playlist", title: "2 Minutes to Midnight", artist: "Iron Maiden", year: 1984, reason: "An '80s heavy metal update on nuclear anxiety. The lyrics are just as graphic, but set to galloping riffs.", youtubeUrl: "https://www.youtube.com/watch?v=9qbRHY1l0vc" }, | |
{ category: "The Apocalypse Playlist", title: "The Man Comes Around", artist: "Johnny Cash", year: 2002, reason: "A chilling, spoken-word recitation of the Book of Revelation. Cash delivers the ultimate apocalyptic prophecy with biblical authority.", youtubeUrl: "https://www.youtube.com/watch?v=k9IfHDi-2EA" }, | |
{ category: "The Raw and The Real", title: "What's Going On", artist: "Marvin Gaye", year: 1971, reason: "Recommended for its raw emotional honesty and its similar 'laundry list' approach to societal ills, delivered as a desperate, soulful plea.", youtubeUrl: "https://www.youtube.com/watch?v=o5Yy2Gf3a4A" }, | |
{ category: "The Raw and The Real", title: "Zombie", artist: "The Cranberries", year: 1994, reason: "Dolores O'Riordan's vocal is a tour de force of raw emotion, cracking with anguish and soaring with rage, making it the primary vehicle for the song's impact.", youtubeUrl: "https://www.youtube.com/watch?v=6Ejga4kJUts" } | |
]; | |
const lyricHighlights = document.querySelectorAll('.lyric-highlight'); | |
const modal = document.getElementById('lyric-modal'); | |
const modalCloseBtn = document.getElementById('modal-close-btn'); | |
const modalTitle = document.getElementById('modal-title'); | |
const modalText = document.getElementById('modal-text'); | |
lyricHighlights.forEach(el => { | |
el.addEventListener('click', () => { | |
const key = el.dataset.lyric; | |
const data = lyricData[key]; | |
if (data) { | |
modalTitle.textContent = data.title; | |
modalText.textContent = data.text; | |
modal.classList.remove('hidden'); | |
modal.classList.add('flex'); | |
} | |
}); | |
}); | |
const closeModal = () => { | |
modal.classList.add('hidden'); | |
modal.classList.remove('flex'); | |
}; | |
modalCloseBtn.addEventListener('click', closeModal); | |
modal.addEventListener('click', (e) => { | |
if (e.target === modal) { | |
closeModal(); | |
} | |
}); | |
const filterButtonsContainer = document.getElementById('filter-buttons'); | |
const songGrid = document.getElementById('song-grid'); | |
const categories = ['All', ...new Set(songData.map(song => song.category))]; | |
categories.forEach(category => { | |
const button = document.createElement('button'); | |
button.className = 'filter-btn px-4 py-2 text-sm font-medium rounded-full transition-colors duration-200'; | |
button.textContent = category; | |
if (category === 'All') { | |
button.classList.add('bg-[#312E2B]', 'text-white'); | |
} else { | |
button.classList.add('bg-gray-200', 'text-gray-700', 'hover:bg-gray-300'); | |
} | |
button.addEventListener('click', () => { | |
filterSongs(category); | |
document.querySelectorAll('.filter-btn').forEach(btn => { | |
btn.classList.remove('bg-[#312E2B]', 'text-white'); | |
btn.classList.add('bg-gray-200', 'text-gray-700', 'hover:bg-gray-300'); | |
}); | |
button.classList.add('bg-[#312E2B]', 'text-white'); | |
button.classList.remove('bg-gray-200', 'text-gray-700', 'hover:bg-gray-300'); | |
}); | |
filterButtonsContainer.appendChild(button); | |
}); | |
const renderSongs = (songs) => { | |
songGrid.innerHTML = ''; | |
songs.forEach(song => { | |
const card = document.createElement('div'); | |
card.className = 'card-flip h-64'; | |
card.innerHTML = ` | |
<div class="card-flip-inner rounded-lg shadow-lg cursor-pointer"> | |
<div class="card-face card-front bg-white p-6 border border-gray-200 rounded-lg text-center"> | |
<h4 class="text-xl font-bold">${song.title}</h4> | |
<p class="text-gray-500">${song.artist} (${song.year})</p> | |
<p class="mt-4 text-xs font-semibold uppercase tracking-wider text-[#B9452C]">${song.category}</p> | |
</div> | |
<div class="card-face card-back bg-gray-800 text-white p-6 rounded-lg flex flex-col justify-center items-center text-center"> | |
<p class="text-sm">${song.reason}</p> | |
<a href="${song.youtubeUrl}" target="_blank" rel="noopener noreferrer" class="mt-4 inline-block bg-[#B9452C] hover:bg-red-800 text-white font-bold py-2 px-4 rounded-full transition-colors duration-300 text-xs uppercase tracking-wider"> | |
Listen on YouTube | |
</a> | |
</div> | |
</div> | |
`; | |
card.addEventListener('click', () => { | |
card.classList.toggle('flipped'); | |
}); | |
songGrid.appendChild(card); | |
}); | |
}; | |
const filterSongs = (category) => { | |
const filteredSongs = category === 'All' | |
? songData | |
: songData.filter(song => song.category === category); | |
renderSongs(filteredSongs); | |
}; | |
filterSongs('All'); | |
const billboardCtx = document.getElementById('billboardChart').getContext('2d'); | |
new Chart(billboardCtx, { | |
type: 'line', | |
data: { | |
labels: ['July W1', 'July W2', 'July W3', 'July W4', 'Aug W1', 'Aug W2', 'Aug W3', 'Aug W4', 'Sept W1', 'Sept W2', 'Sept W3', 'Sept W4'], | |
datasets: [{ | |
label: 'Billboard Hot 100 Position', | |
data: [87, 64, 45, 30, 18, 9, 5, 3, 2, 1, 1, 2], | |
backgroundColor: 'rgba(185, 69, 44, 0.2)', | |
borderColor: '#B9452C', | |
borderWidth: 3, | |
tension: 0.3, | |
pointBackgroundColor: '#B9452C', | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
scales: { | |
y: { | |
beginAtZero: false, | |
reverse: true, | |
min: 1, | |
max: 100, | |
title: { | |
display: true, | |
text: 'Chart Position' | |
} | |
} | |
}, | |
plugins: { | |
legend: { | |
display: false | |
}, | |
tooltip: { | |
callbacks: { | |
label: function(context) { | |
return `Position: #${context.parsed.y}`; | |
} | |
} | |
}, | |
annotation: { | |
annotations: { | |
line1: { | |
type: 'line', | |
yMin: 1, | |
yMax: 1, | |
borderColor: 'rgb(50, 50, 50)', | |
borderWidth: 2, | |
borderDash: [6, 6], | |
label: { | |
content: 'Reaches #1 despite bans', | |
enabled: true, | |
position: 'start' | |
} | |
} | |
} | |
} | |
} | |
} | |
}); | |
const navLinks = document.querySelectorAll('.nav-link'); | |
const sections = document.querySelectorAll('main section'); | |
const observer = new IntersectionObserver((entries) => { | |
entries.forEach(entry => { | |
if (entry.isIntersecting) { | |
navLinks.forEach(link => { | |
link.classList.remove('active'); | |
if (link.getAttribute('href').substring(1) === entry.target.id) { | |
link.classList.add('active'); | |
} | |
}); | |
} | |
}); | |
}, { threshold: 0.5 }); | |
sections.forEach(section => { | |
observer.observe(section); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment