diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} diff --git a/images/pathto.txt b/images/pathto.txt new file mode 100644 index 00000000..df7d3092 --- /dev/null +++ b/images/pathto.txt @@ -0,0 +1 @@ +.\images\cover_art\jinjer_vortex.jpg \ No newline at end of file diff --git a/index.html b/index.html index c55fb482..df3b4ac5 100644 --- a/index.html +++ b/index.html @@ -4,16 +4,13 @@ Awesome MP3 Player - + + -
- -
-
- -
+
+
diff --git a/index.new.html b/index.new.html index eba39f17..bbdb5ed1 100644 --- a/index.new.html +++ b/index.new.html @@ -7,11 +7,12 @@ +

Awesome Player!!!

-

Add a new song

+

Click me to add a new song

diff --git a/leftToDo.txt b/leftToDo.txt new file mode 100644 index 00000000..910ca4e6 --- /dev/null +++ b/leftToDo.txt @@ -0,0 +1,8 @@ +each song is generated an id so it can be played and removed. DoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDone +event listeners inside createElemtn functions, createSongElemnt... + +Time Displayed, bonus. +Double playlists, songs header.DoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDone + +bonus: added songs will remain sorted by title.DoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDoneDone + diff --git a/leftToDo2.txt b/leftToDo2.txt new file mode 100644 index 00000000..516a8955 --- /dev/null +++ b/leftToDo2.txt @@ -0,0 +1,2 @@ +// automatically switches between songs not working +// first click only pauses progress bar but doesn't automatically start next song. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..48e341a0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/scripts/index.js b/scripts/index.js index 6842c794..2948b747 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -1,30 +1,131 @@ +function playlistDuration(id) { + let answer = 0 + const playlists = player.playlists + playlists.forEach((playlist) => { + if (playlist.id === id) { + if (!playlist.songs) return; + playlist.songs.forEach((songNumber) => { + player.songs.forEach((song) => { + // finds songs that match the numbers in the array 'songs' of playlist object + if (song.id === songNumber) { + answer += song.duration + } + }) + }) + } + }) + return answer +} + +function durationConverter(time) { + if (typeof time === "string") { + const arr = time.split(":") + const seconds = +arr[0] * 60 + +(+arr[1]) + return seconds + } else { + let newFormat = new Date(time * 1000).toISOString().substr(14, 5) + return newFormat + } +} /** * Plays a song from the player. * Playing a song means changing the visual indication of the currently playing song. * * @param {String} songId - the ID of the song to play */ -function playSong(songId) { - // Your code here + +function originalPlaySong(songId) { + const resetSongs = document.querySelectorAll(".song-element") + resetSongs.forEach((song) => { + song.setAttribute("style", "background-color: rgb(118, 201, 204)") + }) + player.songs.forEach((song) => { + if (song.id == songId) { + const soughtSong = document.querySelector(".song" + songId) + soughtSong.setAttribute("style", "background-color: rgb(96, 150, 163)") + soughtSong.setAttribute("style", "cursor: pointer") + soughtSong.classList.add("current-song") + } + }) + // index++ + // clearInterval(doesSomething) } +function setColors (songArray) { + for (let i = 0; i < songArray.length; i++) { + const soughtSong = document.querySelector(`.song${songArray[i].id}`) + if (songArray[i].duration < 421 && songArray[i].duration > 119) { + const color = (421 - songArray[i].duration) * (120/420) + soughtSong.setAttribute("style", `background-color: hsl(${color}, 100%, 25%)`) + } else if (songArray[i].duration < 120) { + soughtSong.setAttribute("style", `background-color: green`) + } else { soughtSong.setAttribute("style", `background-color: red`)} + } +} /** * Creates a song DOM element based on a song object. */ function createSongElement({ id, title, album, artist, duration, coverArt }) { const children = [] - const classes = [] - const attrs = { onclick: `playSong(${id})` } + const classes = ["song-element"] + const attrs = {} // onclick: `playSong(${id})` this was once here + const ul = document.createElement("ul") + const image = document.createElement("img") + const playButton = document.createElement('button') + playButton.classList.add('play-button', 'play-button' + id) + playButton.append('⏯') + const removeButton = document.createElement('button') + removeButton.classList.add('remove-button', 'remove-button' + id) + removeButton.append('✖️') + image.src = coverArt + image.alt = 'cover-photo' + for (let key in arguments[0]) { + if (key === 'id' || key === 'coverArt') { + continue + } + if (key === 'duration') { + const li = document.createElement("li") + if (!String(arguments[0][key]).includes(':')) { + li.innerText = durationConverter(arguments[0][key]) + } else { + li.innerText = arguments[0][key] + } + ul.append(li) + } else { + const li = document.createElement("li") + li.innerText = arguments[0][key] + ul.append(li) + } + } + ul.appendChild(image) + const divOfButtons = createElement('div', [playButton, removeButton], ['button-container']) + ul.append(divOfButtons) + children.push(ul) return createElement("div", children, classes, attrs) } - /** * Creates a playlist DOM element based on a playlist object. */ function createPlaylistElement({ id, name, songs }) { + // const newId = arguments[0] + // console.log(arguments[0]); const children = [] - const classes = [] - const attrs = {} + const classes = [name + '-playlist'] + const attrs = { id } + const ul = document.createElement("ul") + for (let key in arguments[0]) { + if (key === 'id') { continue } + if (key === 'songs') { + const li = document.createElement("li") + li.innerText = arguments[0][key].length + ' songs' + ul.append(li) + } else { + const li = document.createElement("li") + li.innerText = arguments[0][key] + ul.append(li) + } + } + children.push(ul) return createElement("div", children, classes, attrs) } @@ -40,8 +141,59 @@ function createPlaylistElement({ id, name, songs }) { * @param {Array} classes - the class list of the new element * @param {Object} attributes - the attributes for the new element */ -function createElement(tagName, children = [], classes = [], attributes = {}) { - // Your code here -} // You can write more code below this line + +// creating a ul with nested li for songs: +const songs = document.getElementById("songs") +const playlists = document.getElementById("playlists") +const siteHeader = document.createElement("header") +const headerContent = document.createElement("h1") +headerContent.innerText = `Gabby's MP3 Player` +const songHeader = document.createElement("h2") +// songHeader.innerText = `Songs` +siteHeader.append(headerContent, songHeader) +document.body.insertBefore(siteHeader, songs) +document.body.insertBefore(makeProgressBar(), songs) + +const playlistHeader = document.createElement("h2") +// playlistHeader.innerText = `Playlists:` +document.body.insertBefore(playlistHeader, playlists) + +// sort songs and playlists using chained ternary +function sortSongsAndPlaylists () { + player.songs.sort((a, b) => (a.title > b.title ? 1 : a.title === b.title ? 0 : -1)) + player.playlists.sort((a, b) => (a.name > b.name ? 1 : a.name === b.name ? 0 : -1)) +} + + +function appendToSongsDiv() { + songs.innerText = '' + sortSongsAndPlaylists(); + player.songs.forEach((song) => { + const newSong = createSongElement(song) + newSong.classList.add("song" + song.id) + // newSong.append(makeProgressBar()) + songs.append(newSong) + }) + // paint songs on load: + setColors(player.songs) +} +appendToSongsDiv() + +function appendToPlaylistsDiv() { + playlists.innerText = '' + sortSongsAndPlaylists() + player.playlists.forEach((playlist) => { + const newPlaylist = createPlaylistElement(playlist) + playlists.append(newPlaylist) + const playListTime = document.createElement("li") + playListTime.innerText = durationConverter(playlistDuration(playlist.id)) + newPlaylist.append(playListTime) + }) +} +appendToPlaylistsDiv() + + + + diff --git a/scripts/index.new.js b/scripts/index.new.js index c3a39c8e..29d2bbf3 100644 --- a/scripts/index.new.js +++ b/scripts/index.new.js @@ -1,3 +1,6 @@ +// adding an event listener to call other functions: +document.addEventListener('click', handleSongClickEvent); + /** * Plays a song from the player. * Playing a song means changing the visual indication of the currently playing song. @@ -5,7 +8,7 @@ * @param {Number} songId - the ID of the song to play */ function playSong(songId) { - // Your code here + // using activateSong } /** @@ -13,15 +16,46 @@ function playSong(songId) { * * @param {Number} songId - the ID of the song to remove */ -function removeSong(songId) { - // Your code here +function removeSong(id) { + document.querySelector('.song' + id).remove() + // this makes sure they aren't re-added when you add a newSong + for (let i = 0; i < player.songs.length; i++) { + if (player.songs[i].id == id) { + player.songs.splice(i, 1) + } + } + for (let i = 0; i < player.playlists.length; i++) { + // if the playlisted is deleted jump to the next + // one/ get out of the loop + if (!player.playlists[i]) continue + if (player.playlists[i].songs.includes(+id)) { + player.playlists[i].songs.splice( + player.playlists[i].songs.indexOf(+id), 1 + ) + } + if (player.playlists[i].songs.length < 1) { + delete player.playlists[i] + } + } + appendToPlaylistsDiv() } +function generateNewId () { + const arrayOfSongs = document.querySelectorAll('.song-element'); + const arrayOfIds = []; + for (let song of arrayOfSongs) { + arrayOfIds.push(song.className.match(/(\d+)/)[0]) + } + const newId = Math.max(...arrayOfIds) + 1; + return newId +} /** * Adds a song to the player, and updates the DOM to match. */ -function addSong({ title, album, artist, duration, coverArt }) { - // Your code here +function addSong({id, title, album, artist, duration, coverArt }) { + const newSong = createSongElement(arguments[0]); + newSong.classList.add('song' + id) + appendToSongsDiv(); } /** @@ -31,7 +65,18 @@ function addSong({ title, album, artist, duration, coverArt }) { * @param {MouseEvent} event - the click event */ function handleSongClickEvent(event) { - // Your code here + const removeButton = event.target.closest('.remove-button'); + const playButton = event.target.closest('.play-button'); + + if (removeButton) { + // this next line takes the id of the song: + const id = removeButton.className.match(/(\d+)/)[0]; + return removeSong(id) + } + if (playButton) { + const id = playButton.className.match(/(\d+)/)[0]; + return activateSong(id) + } } /** @@ -40,29 +85,43 @@ function handleSongClickEvent(event) { * @param {MouseEvent} event - the click event */ function handleAddSongEvent(event) { - // Your code here + const arrayOfInputs = document.querySelectorAll('input') + const songObject = { + id: generateNewId(), + title: arrayOfInputs[0].value, + album: arrayOfInputs[1].value, + artist: arrayOfInputs[2].value, + duration: arrayOfInputs[3].value, + coverArt: arrayOfInputs[4].value + } + for (let i = 0; i < arrayOfInputs.length; i++) { + if (arrayOfInputs[i].value === '') { + throw alert(arrayOfInputs[i].placeholder + ` can't be an empty input`) + } + if (!arrayOfInputs[3].value.includes(':')) { + throw alert('Invalid time format') + } + } + // push the song into the player object + // then it is easy to sort them by their names + player.songs.push(songObject) + // making sure the song is painted in correlation with its duration + player.songs[player.songs.length-1].duration = durationConverter(arrayOfInputs[3].value) + addSong(songObject) } /** * Creates a song DOM element based on a song object. */ -function createSongElement({ id, title, album, artist, duration, coverArt }) { - const children = [] - const classes = [] - const attrs = {} - const eventListeners = {} - return createElement("div", children, classes, attrs, eventListeners) +function createSongElement2({ id, title, album, artist, duration, coverArt }) { + // using old createSongElement function } /** * Creates a playlist DOM element based on a playlist object. */ function createPlaylistElement({ id, name, songs }) { - const children = [] - const classes = [] - const attrs = {} - const eventListeners = {} - return createElement("div", children, classes, attrs, eventListeners) + // using old createSongElement function } /** @@ -78,27 +137,116 @@ function createPlaylistElement({ id, name, songs }) { * @param {Object} attributes - the attributes for the new element * @param {Object} eventListeners - the event listeners on the element */ -function createElement(tagName, children = [], classes = [], attributes = {}, eventListeners = {}) { - // Your code here -} +function createElement(tagName, children = [], classes = [], attributes = {}) { + const element = document.createElement(tagName) + children.forEach((child) => element.append(child)) + element.classList = classes.join(" ") + for (const attr in attributes) { + element.setAttribute(attr, attributes[attr]) + } + return element; +} /** * Inserts all songs in the player as DOM elements into the songs list. */ function generateSongs() { - // Your code here + /// using appendToSongsDiv } /** * Inserts all playlists in the player as DOM elements into the playlists list. */ function generatePlaylists() { - // Your code here + // using appendToPlaylistsDiv } // Creating the page structure -generateSongs() -generatePlaylists() +// generateSongs() +// generatePlaylists() // Making the add-song-button actually do something document.getElementById("add-button").addEventListener("click", handleAddSongEvent) + +function makeProgressBar () { + const myProgress = document.createElement('div'); + const myBar = document.createElement('div'); + myProgress.setAttribute("class", "myProgress"); + myBar.setAttribute("class", "myBar"); + myProgress.append(myBar); + return myProgress +} + + +function activateSong(id) { + const duration = getSongDuration(id) + let tempVar = 0; + function progress () { + if (tempVar == 0) { + tempVar = 1; + const myBar = document.querySelector(".myBar"); + if (!myBar.getAttribute("style")) { + } + else { + document.querySelector('.myBar').remove() + document.body.insertBefore(makeProgressBar(), songs) + activateSong(id) + } + originalPlaySong(id) // keep old playsong alive still + let width = 1; + const interval = setInterval(frame, 10*duration); // progress slowly incrementing + function frame() { + if (width >= 100) { // (if bar is full) stop the function and reset the bar to empty + clearInterval(interval); + tempVar = 0; + } else { + width++; + myBar.style.width = width + "%"; + } + } + } + } + progress() + if (getNextId(id)) { + const timeoutInterval = setTimeout(activateSong, duration*1000, getNextId(id)) + } else { + const finishInterval = setTimeout(appendToSongsDiv, duration*1000) + } +} + +function getSongDuration (id) { + let duration; + player.songs.forEach(song => { + if (song.id == id) { + duration = song.duration + } + }) + return duration +} + +document.querySelector('.click-to-add').addEventListener('click', showInputs) +function showInputs () { + const inputDiv = document.querySelector('#inputs') + const addButton = document.querySelector('#add-button') + if (inputDiv.style.visibility === 'hidden' || (!inputDiv.getAttribute("style"))) { + inputDiv.style.visibility = 'visible' + addButton.style.visibility = 'visible' + } else { + inputDiv.style.visibility = 'hidden' + addButton.style.visibility = 'hidden' + } + +} + +function getNextId (id) { + let nextId; + const songElements = document.querySelectorAll('.song-element') + for (let i = 0; i < songElements.length; i++) { + console.log(); + const currentId = songElements[i].className.match(/(\d+)/)[0]; + if (currentId == id && + currentId != songElements[songElements.length-1].className.match(/(\d+)/)[0]) { + return nextId = songElements[i+1].className.match(/(\d+)/)[0]; + } + } +} \ No newline at end of file diff --git a/style.css b/style.css index f4645fe9..5147e6af 100644 --- a/style.css +++ b/style.css @@ -1 +1,80 @@ -/* Your code here */ +/* Your code here */ +#songs { + display: flex; + flex-wrap: wrap; + margin-top: 100px; + justify-content: space-around; +} + +.song-element { + display: flex; + flex-basis: 20%; +} +.song-element:hover { + color: red; +} +.song-element, #playlists{ + border-radius: 30px; + box-shadow: 5px 10px; + margin: 20px; +} +.button-container { + display: flex; + justify-content: space-around; + align-items: flex-end; +} +.remove-button, .play-button { + background-color: black; +} +.play-button { + background-color: mediumslateblue; +} + +body { + text-align: center; + background-color: rgb(43, 122, 226); +} + +li { + list-style-type: none; + color: black; +} +#playlists, div + h2 { + background-color: rgb(226, 43, 156); +} +.current-song { + background-color: blueviolet; +} + +img { + width: 60%; +} + +button { + /* display: flex; */ + font-size: 150%; + +} + + +.myProgress { + width: 100%; + background-color: grey; + position: sticky; + top: 0; + + } + +.myBar { + width: 1%; + height: 30px; + background-color: red; + } + + .click-to-add:hover { + cursor: pointer; + } + + #inputs, #add-button { + visibility: hidden; + } \ No newline at end of file