<!DOCTYPE html> <html lang="en"> <head> <title>Naomi's Music Library</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="description" content="An interactive explorer for the music Naomi listens to." /> <script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script> </head> <body> <main> <h1>Naomi's Music Library</h1> <section> <p>An interactive explorer for the music Naomi listens to.</p> <p id="count">Loading library...</p> </section> <div style="display: none;"> <span>Search Artists: </span> <input type="text" id="artist" /> </div> <div style="display: none;"> <span>Search Titles: </span> <input type="text" id="title" /> </div> <div style="display: none;"> <button type="button" id="clear">Clear Filters</button> </div> <table id="songs"> </table> </main> </body> <script> const artistQuery = document.getElementById('artist'); const titleQuery = document.getElementById('title'); const resetButton = document.getElementById('clear'); const songTable = document.getElementById('songs'); const filterSongs = (artist, title) => { let result = [...songList]; if(artist) { result = result.filter(song => song.artist.toLowerCase().includes(artist.toLowerCase())); } if(title) { result = result.filter(song => song.title.toLowerCase().includes(title.toLowerCase())); } resetButton.parentElement.style.display = artist || title ? "block" : "none"; document.getElementById('count').innerText = artist || title ? `Filtered to ${result.length} songs from ${songList.length}.` : `Naomi currently has ${songList.length} songs.`; updateTable(result); } const loadSongs = (songs) => { songList.push(...songs); artistQuery.value = ""; titleQuery.value = ""; artistQuery.parentElement.style.display = "block"; titleQuery.parentElement.style.display = "block"; document.getElementById('count').innerText = `Naomi currently has ${songs.length} songs.`; updateTable(songs); } const updateTable = (songs) => { songs = songs.sort((a, b) => a.title.localeCompare(b.title)); songTable.innerHTML = ""; const header = document.createElement('tr'); const artistHeader = document.createElement('th'); artistHeader.innerText = "Artist"; const titleHeader = document.createElement('th'); titleHeader.innerText = "Title"; header.appendChild(titleHeader); header.appendChild(artistHeader); songTable.appendChild(header); songs.forEach(song => { const row = document.createElement('tr'); const artist = document.createElement('td'); artist.innerText = song.artist; const title = document.createElement('td'); title.innerText = song.title; row.appendChild(title); row.appendChild(artist); songTable.appendChild(row); }); } const songList = []; fetch("./songs.json").then(res => res.json()).then(data => loadSongs(data)) artistQuery?.addEventListener("input", (e) => filterSongs(e.target.value, titleQuery.value)); titleQuery?.addEventListener("input", (e) => filterSongs(artistQuery.value, e.target.value)); resetButton?.addEventListener("click", () => { artistQuery.value = ""; titleQuery.value = ""; filterSongs("", ""); }); </script> <style> table { width: 100%; border-collapse: collapse; } tr:nth-of-type(even) { background-color: #db7093dd; color: #ffefef; } input { background:var(--foreground); color:var(--background); border:1px solid white; border-radius:10px; padding:.25rem } button { background:var(--foreground); color:var(--background); border:1px solid white; border-radius:10px; padding:.25rem; cursor:url('https://cdn.nhcarrigan.com/cursors/pointer.cur'), pointer; } </style> </html>