From 43759abf45a8f2b9fc7526efcb88f4dc14cbb687 Mon Sep 17 00:00:00 2001 From: Kolade Chris <65571316+Ksound22@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:06:24 +0100 Subject: [PATCH] feat: adding music player project (#52487) Co-authored-by: larymak Co-authored-by: Sem Bauke Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com> Co-authored-by: Krzysztof G. <60067306+gikf@users.noreply.github.com> Co-authored-by: Kristofer Koishigawa --- client/i18n/locales/english/intro.json | 12 +- .../index.md | 10 + .../meta.json | 349 ++++ .../652f948489abbb81e6bf5a01.md | 558 ++++++ .../652fa2aee6374ad29b5d49b4.md | 559 ++++++ .../652fa3c4968fa9d6f8f6d873.md | 532 ++++++ .../65327e9c7ea42e125256b29a.md | 614 +++++++ .../653281af14be5f2055310f8e.md | 607 +++++++ .../653283d07b8f9d294aafa83b.md | 661 +++++++ .../65362bfd67d61d517deef191.md | 669 ++++++++ .../653635c731206b718659d3d5.md | 652 +++++++ .../653639d63a45a077333312c8.md | 650 +++++++ .../653641509b6e7681a9333245.md | 648 +++++++ .../65364566e84e378837fbaf2a.md | 665 ++++++++ .../653fb19b515fde28243f727a.md | 660 +++++++ .../65420b821b14f25a6b35c3b3.md | 641 +++++++ .../65420dcfc60580678dad7a92.md | 636 +++++++ .../654210a9eda99477f5697a94.md | 640 +++++++ .../654212b82fb5cf872f77148f.md | 648 +++++++ .../654213f2fad2d48f74d6c239.md | 642 +++++++ .../654215fe7b4a899ddceb3b60.md | 639 +++++++ .../654218753c255fabb81f57ca.md | 653 +++++++ .../65422ba173a18b1bedef1bb6.md | 662 +++++++ .../6552127b2576c2fbc5ecc2ea.md | 672 ++++++++ .../65521badc7b7470edf952372.md | 680 ++++++++ .../65521ec3bb117c195c4f6cb5.md | 668 ++++++++ .../655220a3fa5c3c200bc8e938.md | 677 ++++++++ .../6552303a9a78704f8ff072e9.md | 679 ++++++++ .../655235c2e607297f00316650.md | 656 +++++++ .../6552385244ccf89b77d6b332.md | 689 ++++++++ .../655243068222c2c1166b90b0.md | 689 ++++++++ .../655476e1ff522252fdcce5e4.md | 694 ++++++++ .../655479aa3e1e0360ae38b7a6.md | 699 ++++++++ .../65547ee197840478a1b95f4b.md | 695 ++++++++ .../6554815fe2472f8bfdab7642.md | 701 ++++++++ .../655482742cc5499726e3f347.md | 713 ++++++++ .../655483ebf0096ba02b2c3d4c.md | 701 ++++++++ .../655485321913feabbc5f00f8.md | 705 ++++++++ .../6554860ea4dfbab2f4786fc8.md | 720 ++++++++ .../655487f686aabfc2a10ba887.md | 689 ++++++++ .../65548f747a4cdafd186948d1.md | 712 ++++++++ .../655490f55c36900779336988.md | 726 ++++++++ .../655492e6b90c7a198c587943.md | 719 ++++++++ .../655494d5a15d6a2567e1ea60.md | 708 ++++++++ .../655495a6bd96e42bc3baa795.md | 726 ++++++++ .../6555d17af9ff06a14d399f6d.md | 736 ++++++++ .../6555d458687cb3b357834df9.md | 730 ++++++++ .../6555d729c9bfd7c3195f1948.md | 745 ++++++++ .../6555d7e384056dc9c581fadf.md | 719 ++++++++ .../6555d8faed60b9d3e4a6cefb.md | 739 ++++++++ .../6555dd138e70cae6b546966d.md | 735 ++++++++ .../6555de565387a2efe90a6ccc.md | 742 ++++++++ .../6555e04aeb225bfbae237344.md | 727 ++++++++ .../6555e0bfe4d69904410f7cd3.md | 749 ++++++++ .../6555e39a5f4c6f138c7d9405.md | 767 +++++++++ .../6555e57d3e6d9d221c4735be.md | 740 ++++++++ .../6555e6cec786da2aadc11ea0.md | 761 +++++++++ .../6555e7acdbae972d3e8e0f5b.md | 754 ++++++++ .../6555e9197bf1d7416bdd76e0.md | 768 +++++++++ .../6555ebf07ec610585a626f72.md | 779 +++++++++ .../65571e742fbf4532d8f98e90.md | 767 +++++++++ .../655720534347cb3f31cdfb3d.md | 752 ++++++++ .../65572399a8e16d50bc2c1ff3.md | 777 +++++++++ .../655724bac464795a0ad91082.md | 760 +++++++++ .../655727b2e1e49d6adf584442.md | 791 +++++++++ .../655729e68e49b277a6b448bd.md | 779 +++++++++ .../65572bb34a7e488224b937fc.md | 795 +++++++++ .../65572e5aaf022790fb4a81b1.md | 782 +++++++++ .../655737cd004591b0271d6826.md | 779 +++++++++ .../65573a97c59ddbbf028ca95e.md | 798 +++++++++ .../65573d0abe4d38cd6fa13f44.md | 795 +++++++++ .../6557421eb6a7a0f0500e3106.md | 756 ++++++++ .../655b49333d9f265bc1512152.md | 761 +++++++++ .../655b4bbff1dbf66cb2ed4dac.md | 753 ++++++++ .../655b4c8f636d9675953a0388.md | 769 +++++++++ .../655b4dad1d38ff7cdd65cbfe.md | 1515 +++++++++++++++++ .../655dc43318591b975cdfe2d8.md | 576 +++++++ .../65606d06666e118ba86162be.md | 584 +++++++ .../65606ed6ea2baca053327e9b.md | 586 +++++++ .../656071d679089ebd9d5035a0.md | 618 +++++++ .../656073a2b98232c8aca72267.md | 620 +++++++ .../656472ed8f552d2f2b3f7883.md | 659 +++++++ .../6567055f59d39f07d1c542dc.md | 634 +++++++ .../65671421254eeb489875cdd8.md | 711 ++++++++ .../65672136535209761a5cf02b.md | 660 +++++++ .../65672adafbaa37a6cef886f7.md | 788 +++++++++ 86 files changed, 59080 insertions(+), 1 deletion(-) create mode 100644 client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md create mode 100644 curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md create mode 100644 curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 3beb0672b3d..2362b777d06 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -429,6 +429,13 @@ "Working with asynchronous programming is a core fundamental of JavaScript. In this project, you will gain proficiency in asynchronous concepts by building a freeCodeCamp forum leaderboard.", "This project will cover the Fetch API, promises, Async/Await, and the try...catch statement." ] + }, + "learn-basic-string-and-array-methods-by-building-a-music-player": { + "title": "Learn Basic String and Array Methods by Building a Music Player", + "intro": [ + "Mastering essential string and array methods like the find(), forEach(), map(), and join() methods is crucial for developing dynamic web applications.", + "In this project you will build out a basic MP3 player using HTML, CSS, and JavaScript. The project covers fundamental concepts such as handling audio playback, managing a playlist, implementing play, pause, next, previous, and shuffle functionalities, as well as dynamically updating the user interface based on the current song." + ] } } }, @@ -528,7 +535,10 @@ "In these projects, you'll need to fetch data and parse a dataset, then use D3 to create different data visualizations. Finish them all to earn your Data Visualization certification." ] }, - "d3-dashboard": { "title": "D3 Dashboard", "intro": ["", ""] } + "d3-dashboard": { + "title": "D3 Dashboard", + "intro": ["", ""] + } } }, "relational-database": { diff --git a/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md new file mode 100644 index 00000000000..011e8042ffd --- /dev/null +++ b/client/src/pages/learn/2022/javascript-algorithms-and-data-structures/learn-basic-string-and-array-methods-by-building-a-music-player/index.md @@ -0,0 +1,10 @@ +--- +title: Introduction to the Learn Basic String and Array Methods by Building a Music Player +block: learn-basic-string-and-array-methods-by-building-a-music-player +superBlock: 2022/javascript-algorithms-and-data-structures +isBeta: true +--- + +## Introduction to the Learn Basic String and Array Methods by Building a Music Player + +This is a test for the new project-based curriculum. diff --git a/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json b/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json new file mode 100644 index 00000000000..924f50874e7 --- /dev/null +++ b/curriculum/challenges/_meta/learn-basic-string-and-array-methods-by-building-a-music-player/meta.json @@ -0,0 +1,349 @@ +{ + "name": "Learn Basic String and Array Methods by Building a Music Player", + "isUpcomingChange": true, + "usesMultifileEditor": true, + "hasEditableBoundaries": true, + "dashedName": "learn-basic-string-and-array-methods-by-building-a-music-player", + "order": 70, + "time": "5 hours", + "template": "", + "required": [], + "superBlock": "2022/javascript-algorithms-and-data-structures", + "superOrder": 4, + "isBeta": true, + "challengeOrder": [ + { + "id": "652f948489abbb81e6bf5a01", + "title": "Step 1" + }, + { + "id": "652fa2aee6374ad29b5d49b4", + "title": "Step 2" + }, + { + "id": "652fa3c4968fa9d6f8f6d873", + "title": "Step 3" + }, + { + "id": "655dc43318591b975cdfe2d8", + "title": "Step 4" + }, + { + "id": "65606d06666e118ba86162be", + "title": "Step 5" + }, + { + "id": "65606ed6ea2baca053327e9b", + "title": "Step 6" + }, + { + "id": "65327e9c7ea42e125256b29a", + "title": "Step 7" + }, + { + "id": "653281af14be5f2055310f8e", + "title": "Step 8" + }, + { + "id": "656071d679089ebd9d5035a0", + "title": "Step 9" + }, + { + "id": "656073a2b98232c8aca72267", + "title": "Step 10" + }, + { + "id": "653fb19b515fde28243f727a", + "title": "Step 11" + }, + { + "id": "65420b821b14f25a6b35c3b3", + "title": "Step 12" + }, + { + "id": "65420dcfc60580678dad7a92", + "title": "Step 13" + }, + { + "id": "654210a9eda99477f5697a94", + "title": "Step 14" + }, + { + "id": "654212b82fb5cf872f77148f", + "title": "Step 15" + }, + { + "id": "654213f2fad2d48f74d6c239", + "title": "Step 16" + }, + { + "id": "654215fe7b4a899ddceb3b60", + "title": "Step 17" + }, + { + "id": "6567055f59d39f07d1c542dc", + "title": "Step 18" + }, + { + "id": "654218753c255fabb81f57ca", + "title": "Step 19" + }, + { + "id": "653283d07b8f9d294aafa83b", + "title": "Step 20" + }, + { + "id": "65362bfd67d61d517deef191", + "title": "Step 21" + }, + { + "id": "653635c731206b718659d3d5", + "title": "Step 22" + }, + { + "id": "653639d63a45a077333312c8", + "title": "Step 23" + }, + { + "id": "656472ed8f552d2f2b3f7883", + "title": "Step 24" + }, + { + "id": "653641509b6e7681a9333245", + "title": "Step 25" + }, + { + "id": "655235c2e607297f00316650", + "title": "Step 26" + }, + { + "id": "65364566e84e378837fbaf2a", + "title": "Step 27" + }, + { + "id": "65422ba173a18b1bedef1bb6", + "title": "Step 28" + }, + { + "id": "6552127b2576c2fbc5ecc2ea", + "title": "Step 29" + }, + { + "id": "65672136535209761a5cf02b", + "title": "Step 30" + }, + { + "id": "65521badc7b7470edf952372", + "title": "Step 31" + }, + { + "id": "65521ec3bb117c195c4f6cb5", + "title": "Step 32" + }, + { + "id": "655220a3fa5c3c200bc8e938", + "title": "Step 33" + }, + { + "id": "6552303a9a78704f8ff072e9", + "title": "Step 34" + }, + { + "id": "655487f686aabfc2a10ba887", + "title": "Step 35" + }, + { + "id": "6552385244ccf89b77d6b332", + "title": "Step 36" + }, + { + "id": "655243068222c2c1166b90b0", + "title": "Step 37" + }, + { + "id": "655476e1ff522252fdcce5e4", + "title": "Step 38" + }, + { + "id": "655479aa3e1e0360ae38b7a6", + "title": "Step 39" + }, + { + "id": "65547ee197840478a1b95f4b", + "title": "Step 40" + }, + { + "id": "6554815fe2472f8bfdab7642", + "title": "Step 41" + }, + { + "id": "655482742cc5499726e3f347", + "title": "Step 42" + }, + { + "id": "655483ebf0096ba02b2c3d4c", + "title": "Step 43" + }, + { + "id": "655485321913feabbc5f00f8", + "title": "Step 44" + }, + { + "id": "6554860ea4dfbab2f4786fc8", + "title": "Step 45" + }, + { + "id": "65548f747a4cdafd186948d1", + "title": "Step 46" + }, + { + "id": "655490f55c36900779336988", + "title": "Step 47" + }, + { + "id": "65671421254eeb489875cdd8", + "title": "Step 48" + }, + { + "id": "655492e6b90c7a198c587943", + "title": "Step 49" + }, + { + "id": "655494d5a15d6a2567e1ea60", + "title": "Step 50" + }, + { + "id": "655495a6bd96e42bc3baa795", + "title": "Step 51" + }, + { + "id": "6555d17af9ff06a14d399f6d", + "title": "Step 52" + }, + { + "id": "6555d458687cb3b357834df9", + "title": "Step 53" + }, + { + "id": "6555d729c9bfd7c3195f1948", + "title": "Step 54" + }, + { + "id": "6555d7e384056dc9c581fadf", + "title": "Step 55" + }, + { + "id": "6555d8faed60b9d3e4a6cefb", + "title": "Step 56" + }, + { + "id": "6555dd138e70cae6b546966d", + "title": "Step 57" + }, + { + "id": "6555de565387a2efe90a6ccc", + "title": "Step 58" + }, + { + "id": "6555e04aeb225bfbae237344", + "title": "Step 59" + }, + { + "id": "6555e0bfe4d69904410f7cd3", + "title": "Step 60" + }, + { + "id": "6555e39a5f4c6f138c7d9405", + "title": "Step 61" + }, + { + "id": "6555e57d3e6d9d221c4735be", + "title": "Step 62" + }, + { + "id": "6555e6cec786da2aadc11ea0", + "title": "Step 63" + }, + { + "id": "6555e7acdbae972d3e8e0f5b", + "title": "Step 64" + }, + { + "id": "6555e9197bf1d7416bdd76e0", + "title": "Step 65" + }, + { + "id": "6555ebf07ec610585a626f72", + "title": "Step 66" + }, + { + "id": "65571e742fbf4532d8f98e90", + "title": "Step 67" + }, + { + "id": "655720534347cb3f31cdfb3d", + "title": "Step 68" + }, + { + "id": "65572399a8e16d50bc2c1ff3", + "title": "Step 69" + }, + { + "id": "6557421eb6a7a0f0500e3106", + "title": "Step 70" + }, + { + "id": "655724bac464795a0ad91082", + "title": "Step 71" + }, + { + "id": "655727b2e1e49d6adf584442", + "title": "Step 72" + }, + { + "id": "65672adafbaa37a6cef886f7", + "title": "Step 73" + }, + { + "id": "655729e68e49b277a6b448bd", + "title": "Step 74" + }, + { + "id": "65572bb34a7e488224b937fc", + "title": "Step 75" + }, + { + "id": "65572e5aaf022790fb4a81b1", + "title": "Step 76" + }, + { + "id": "655737cd004591b0271d6826", + "title": "Step 77" + }, + { + "id": "65573a97c59ddbbf028ca95e", + "title": "Step 78" + }, + { + "id": "65573d0abe4d38cd6fa13f44", + "title": "Step 79" + }, + { + "id": "655b49333d9f265bc1512152", + "title": "Step 80" + }, + { + "id": "655b4bbff1dbf66cb2ed4dac", + "title": "Step 81" + }, + { + "id": "655b4c8f636d9675953a0388", + "title": "Step 82" + }, + { + "id": "655b4dad1d38ff7cdd65cbfe", + "title": "Step 83" + } + ], + "helpCategory": "JavaScript" +} \ No newline at end of file diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md new file mode 100644 index 00000000000..a2bbdcc90fd --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652f948489abbb81e6bf5a01.md @@ -0,0 +1,558 @@ +--- +id: 652f948489abbb81e6bf5a01 +title: Step 1 +challengeType: 0 +dashedName: step-1 +--- + +# --description-- + +In this project you will learn basic string and array methods by building a music player app. You will be able to play, pause, skip, and shuffle songs. + +The HTML and CSS of this project have been provided for you, so you can focus on the JavaScript. + +Start by accessing the `#playlist-songs`, `#play`, and `#pause` elements with the `getElementById()` method. Assign them to variables `playlistSongs`, `playButton` and `pauseButton` respectively. + + +# --hints-- + +You should use `document.getElementById()` to get the `#playlist-songs` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)playlist\-songs\1\)/); +``` + +You should assign the `#playlist-songs` element to the variable `playlistSongs`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+playlistSongs\s*\=\s*document\.getElementById\(\s*('|"|`)playlist\-songs\1\)/); +``` + +You should use `document.getElementById()` to get the `#play` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)play\1\)/); +``` + +You should assign the `#play` element to the variable `playButton`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+playButton\s*\=\s*document\.getElementById\(\s*('|"|`)play\1\)/); +``` + +You should use `document.getElementById()` to get the `#pause` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)pause\1\)/); +``` + +You should assign the `#pause` element to the variable `pauseButton`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+pauseButton\s*\=\s*document\.getElementById\(\s*('|"|`)pause\1\)/); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
+
+
+
+
+
+
+

freeCodeCamp

+
+
+
+
+
+
+
+ song cover art +
+
+
+

+

+
+
+ + + + + +
+
+
+
+
+
+
+
+
+
+

Playlist

+
+
+
+
+
+
    +
    +
    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md new file mode 100644 index 00000000000..ce95018b8fd --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa2aee6374ad29b5d49b4.md @@ -0,0 +1,559 @@ +--- +id: 652fa2aee6374ad29b5d49b4 +title: Step 2 +challengeType: 0 +dashedName: step-2 +--- + +# --description-- + +Continuing with the pattern, access the `#next`, `#previous` and `#shuffle` elements from the HTML file. + +Assign them to the `nextButton`, `previousButton`, and `shuffleButton` variables respectively. + +# --hints-- + +You should use `document.getElementById()` to get the `#next` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)next\1\)/); +``` + +You should assign the `#next` element to the variable `nextButton`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+nextButton\s*\=\s*document\.getElementById\(\s*('|"|`)next\1\)/); +``` + +You should use `document.getElementById()` to get the `#previous` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)previous\1\)/); +``` + +You should assign the `#previous` element to the variable `previousButton`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+previousButton\s*\=\s*document\.getElementById\(\s*('|"|`)previous\1\)/); +``` + +You should use `document.getElementById()` to get the `#shuffle` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)shuffle\1\)/); +``` + +You should assign the `#shuffle` element to the variable `shuffleButton`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+shuffleButton\s*\=\s*document\.getElementById\(\s*('|"|`)shuffle\1\)/); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
    +
    +
    +
    +
    +
    +
    +

    freeCodeCamp

    +
    +
    +
    +
    +
    +
    +
    + song cover art +
    +
    +
    +

    +

    +
    +
    + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Playlist

    +
    +
    +
    +
    +
    +
      +
      +
      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md new file mode 100644 index 00000000000..a16b4acf194 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/652fa3c4968fa9d6f8f6d873.md @@ -0,0 +1,532 @@ +--- +id: 652fa3c4968fa9d6f8f6d873 +title: Step 3 +challengeType: 0 +dashedName: step-3 +--- + +# --description-- + +Next, create an array to store all the songs. + +Create an empty `allSongs` array. + +# --hints-- + +You should use `const` to create an empty `allSongs` array. + +```js +assert.match(code, /const\s+allSongs\s*=\s*\[\s*\]/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
      +
      +
      +
      +
      +
      +
      +

      freeCodeCamp

      +
      +
      +
      +
      +
      +
      +
      + song cover art +
      +
      +
      +

      +

      +
      +
      + + + + + +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      +

      Playlist

      +
      +
      +
      +
      +
      +
        +
        +
        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md new file mode 100644 index 00000000000..ed737e6f83a --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65327e9c7ea42e125256b29a.md @@ -0,0 +1,614 @@ +--- +id: 65327e9c7ea42e125256b29a +title: Step 7 +challengeType: 0 +dashedName: step-7 +--- + +# --description-- + +All the songs are now in the `allSongs` array. The next step is to initialize the Web Audio API. + +The Audio API is a component of the Web Audio API specification, offering a high-level interface for processing and synthesizing audio within web applications. + +Use `const` to create a variable named `audio` and set it equal to `new Audio()`. This will create a new HTML5 audio element. + +# --hints-- + +You should use the `new` keyword to intialize the web audio API + +```js +assert.match(code, /new\s*Audio\(\);?/) +``` + +You should set the intialization to a constant named `audio`. + +```js +assert.match(code, /const\s+audio\s*=\s*new\s*Audio\(\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
        +
        +
        +
        +
        +
        +
        +

        freeCodeCamp

        +
        +
        +
        +
        +
        +
        +
        + song cover art +
        +
        +
        +

        +

        +
        +
        + + + + + +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Playlist

        +
        +
        +
        +
        +
        +
          +
          +
          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md new file mode 100644 index 00000000000..72d4d0beec4 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653281af14be5f2055310f8e.md @@ -0,0 +1,607 @@ +--- +id: 653281af14be5f2055310f8e +title: Step 8 +challengeType: 0 +dashedName: step-8 +--- + +# --description-- + +Create a `userData` object that will contain the songs, the current song playing, and the time of the current song. + +Declare an empty `userData` object using the `let` keyword. + +# --hints-- + +You should use the `let` keyword to create an empty `userData` object. + +```js +assert.match(code, /let\s*userData\s*=\s*\{\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
          +
          +
          +
          +
          +
          +
          +

          freeCodeCamp

          +
          +
          +
          +
          +
          +
          +
          + song cover art +
          +
          +
          +

          +

          +
          +
          + + + + + +
          +
          +
          +
          +
          +
          +
          +
          +
          +
          +

          Playlist

          +
          +
          +
          +
          +
          +
            +
            +
            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md new file mode 100644 index 00000000000..6478aa494bf --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653283d07b8f9d294aafa83b.md @@ -0,0 +1,661 @@ +--- +id: 653283d07b8f9d294aafa83b +title: Step 20 +challengeType: 0 +dashedName: step-20 +--- + +# --description-- + +It's time to begin implementing the functionality for playing the displayed songs. + +Define a `playSong` function using `const`. The function should take an `id` parameter which will represent the unique identifier of the song you want to play. + +# --hints-- + +You should use `const` to create an empty function named `playSong`. + +```js +assert.match(code, /const\s+playSong\s*=\s*/) +``` + +`playSong` should be a function. + +```js +assert.isFunction(playSong) +``` + +Your `playSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+playSong\s*=\s*\(.*\)\s*=>\s*/) +``` + +Your `playSong` function should take an `id` parameter. + +```js +assert.match(code, /const\s+playSong\s*=\s*\(id/) +``` + +Your `playSong` function should be empty. + +```js +assert.match(code, /const\s+playSong\s*=\s*\(id\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
            +
            +
            +
            +
            +
            +
            +

            freeCodeCamp

            +
            +
            +
            +
            +
            +
            +
            + song cover art +
            +
            +
            +

            +

            +
            +
            + + + + + +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            +

            Playlist

            +
            +
            +
            +
            +
            +
              +
              +
              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
            • + + +
            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md new file mode 100644 index 00000000000..eee366340dd --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65362bfd67d61d517deef191.md @@ -0,0 +1,669 @@ +--- +id: 65362bfd67d61d517deef191 +title: Step 21 +challengeType: 0 +dashedName: step-21 +--- + +# --description-- + +The find() method retrieves the first element within an array that fulfills the conditions specified in the provided callback function. If no element satisfies the condition, the method returns `undefined`. + +In the example below, the `find()` method is used to find the first number greater than 25: + +```js +const numbers = [10, 20, 30, 40, 50]; + +// Find the first number greater than 25 +const foundNumber = numbers.find((number) => number > 25); +console.log(foundNumber); // Output: 30 +``` + +Use `const` to create a variable named `song` and assign it result of the `find()` method call on the `userData?.songs` array. Use `song` as the parameter of the `find()` callback and check if `song.id` is strictly equal to `id`. + +This will iterate through the `userData?.songs` array, searching for a song that corresponds to the `id` passed into the `playSong` function. + +# --hints-- + +You should use the `find` method on `userData?.songs`. + +```js +assert.match(code, /userData\?\.songs\.find\(/) +``` + +Your `find` method should have `song` as the parameter of its arrow function callback. + +```js +assert.match(code, /userData\?\.songs\.find\(\(?song\)?/) +``` + +Your `find` method should use strict equality to check if `song.id` is equal to `id`. + +```js +assert.match(code, /userData\?\.songs\.find\(\(?song\)?\s*=>\s*song.id\s*===\s*id\);?|userData\?\.songs\.find\(\(?song\)?\s*=>\s*id\s*===\s*song\.id\);?/) +``` + +Your `find` method should be assigned to a `song` constant. + +```js +assert.match(code, /const\s*song\s*=\s*userData\?\.songs\.find\(\(?song\)?\s*=>\s*song.id\s*===\s*id\);?|userData\?\.songs\.find\(\(?song\)?\s*=>\s*id\s*===\s*song\.id\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
              +
              +
              +
              +
              +
              +
              +

              freeCodeCamp

              +
              +
              +
              +
              +
              +
              +
              + song cover art +
              +
              +
              +

              +

              +
              +
              + + + + + +
              +
              +
              +
              +
              +
              +
              +
              +
              +
              +

              Playlist

              +
              +
              +
              +
              +
              +
                +
                +
                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +--fcc-editable-region-- +const playSong = (id) => { + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
              • + + +
              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md new file mode 100644 index 00000000000..166afe8a4eb --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653635c731206b718659d3d5.md @@ -0,0 +1,652 @@ +--- +id: 653635c731206b718659d3d5 +title: Step 22 +challengeType: 0 +dashedName: step-22 +--- + +# --description-- + +Inside the `playSong` function, set the `audio.src` property equal to `song.src`. This tells the audio element where to find the audio data for the selected song. + +Also, set the `audio.title` property equal to `song.title`. This tells the audio element what to display as the title of the song. + +# --hints-- + +You should not modify the exist `playSong` function and its content. + +```js +assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?/) +``` + +You should set `audio.src` to `song.src`. + +```js +assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?\s*audio\.src\s*=\s*song\.src;?/) +``` + +You should set `audio.title` to `song.title`. + +```js +assert.match(code, /const\s*playSong\s*=\s*\(id\)\s*=>\s*\{\s*const\s*song\s*=\s*userData\?\.songs\.find\(\(song\)\s=>\s*song.id\s===\s*id\);?\s*audio\.src\s*=\s*song\.src;?\s*audio\.title\s*=\s*song\.title;?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                +
                +
                +
                +
                +
                +
                +

                freeCodeCamp

                +
                +
                +
                +
                +
                +
                +
                + song cover art +
                +
                +
                +

                +

                +
                +
                + + + + + +
                +
                +
                +
                +
                +
                +
                +
                +
                +
                +

                Playlist

                +
                +
                +
                +
                +
                +
                  +
                  +
                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +--fcc-editable-region-- +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                • + + +
                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md new file mode 100644 index 00000000000..bd5796d816d --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653639d63a45a077333312c8.md @@ -0,0 +1,650 @@ +--- +id: 653639d63a45a077333312c8 +title: Step 23 +challengeType: 0 +dashedName: step-23 +--- + +# --description-- + +Before playing the song, you need to make sure it starts from the beginning. This can be achieved by the use of the `currentTime` property of the `audio` object. + +Add an `if` statement to check whether the `userData?.currentSong` is `null` or if `userData?.currentSong.id` is strictly not equal `song.id`. Inside `if` block, set the `currentTime` property of the `audio` object to `0`. + + +# --hints-- + +You should create an `if` statement with the condition `userData?.currentSong === null || userData?.currentSong.id !== song.id`. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*/) +``` + +You should set `audio.currentTime` to `0` inside your `if` block. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                  +
                  +
                  +
                  +
                  +
                  +
                  +

                  freeCodeCamp

                  +
                  +
                  +
                  +
                  +
                  +
                  +
                  + song cover art +
                  +
                  +
                  +

                  +

                  +
                  +
                  + + + + + +
                  +
                  +
                  +
                  +
                  +
                  +
                  +
                  +
                  +
                  +

                  Playlist

                  +
                  +
                  +
                  +
                  +
                  +
                    +
                    +
                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + --fcc-editable-region-- + + --fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                  • + + +
                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md new file mode 100644 index 00000000000..90ecb99e8d0 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653641509b6e7681a9333245.md @@ -0,0 +1,648 @@ +--- +id: 653641509b6e7681a9333245 +title: Step 25 +challengeType: 0 +dashedName: step-25 +--- + +# --description-- + +You need to update the current song being played as well as the appearance of the `playButton` element. + +Start by accessing the `userData` object and its `currentSong` property. Set its value equal to the `song` variable. + +# --hints-- + +You should set `userData.currentSong` to `song`. + +```js +assert.match(code, /userData\.currentSong\s*=\s*song;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +

                    freeCodeCamp

                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    + song cover art +
                    +
                    +
                    +

                    +

                    +
                    +
                    + + + + + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    +

                    Playlist

                    +
                    +
                    +
                    +
                    +
                    +
                      +
                      +
                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + --fcc-editable-region-- + + --fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                    • + + +
                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md new file mode 100644 index 00000000000..bd8e3a93a28 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65364566e84e378837fbaf2a.md @@ -0,0 +1,665 @@ +--- +id: 65364566e84e378837fbaf2a +title: Step 27 +challengeType: 0 +dashedName: step-27 +--- + +# --description-- + +You need to hook up the `playSong` function to a `click` event listener so the songs will start playing when the play button is clicked. + +Add a click event listener to the `playButton` element, then use arrow syntax to pass in a callback with an empty pair of curly braces. + +# --hints-- + +You should call the `addEventListener()` method on your `playButton` variable. + +```js +assert.match(code, /playButton\.addEventListener\(/) +``` + +Your event listener should listen for a `click` event. + +```js +assert.match(code, /playButton\.addEventListener\(('|"|`)click\1/) +``` + +You should use arrow syntax to pass in an empty callback into your event listener. Don't forget you also need an empty pair of curly braces. + +```js +assert.match(code, /playButton\.addEventListener\(('|"|`)click\1,\s*\(\)\s*=>\s*\{\s*\}\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                      +
                      +
                      +
                      +
                      +
                      +
                      +

                      freeCodeCamp

                      +
                      +
                      +
                      +
                      +
                      +
                      +
                      + song cover art +
                      +
                      +
                      +

                      +

                      +
                      +
                      + + + + + +
                      +
                      +
                      +
                      +
                      +
                      +
                      +
                      +
                      +
                      +

                      Playlist

                      +
                      +
                      +
                      +
                      +
                      +
                        +
                        +
                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                      • + + +
                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + + --fcc-editable-region-- + + --fcc-editable-region-- + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md new file mode 100644 index 00000000000..7017506b68e --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/653fb19b515fde28243f727a.md @@ -0,0 +1,660 @@ +--- +id: 653fb19b515fde28243f727a +title: Step 11 +challengeType: 0 +dashedName: step-11 +--- + +# --description-- + +Now you need to show songs to be played in the UI. For this, you'll need to create a `renderSongs` function with an arrow function syntax. + +An arrow function is a shorter and more concise way to write functions in JavaScript. It uses the variable keywords (`var`, `let`, and `const`) and fat arrow syntax (`=>`): + +```js +// Traditional function +function add(a, b) { + return a + b; +} +console.log(add(3, 5)); // Output: 8 + +// Arrow function +const addArrow = (a, b) => { + return a + b +}; +console.log(addArrow(3, 5)); // Output: 8 +``` + +If the function body consists of a single expression, you don't need the curly braces and the `return` keyword. This is called an `implicit return`. + +```js +const addArrow = (a, b) => a + b; +console.log(addArrow(3, 5)); // Output: 8 +``` + +Use the arrow function syntax to create a `renderSongs` function that takes in `array` as its parameter. + +# --hints-- + +You should use `const` to create an empty function named `renderSongs`. + +```js +assert.match(code, /const\s+renderSongs\s*=\s*/) +``` + +`renderSongs` should be a function. + +```js +assert.isFunction(renderSongs) +``` + +Your `renderSongs` function should use an arrow syntax. + +```js +assert.match(code, /const\s+renderSongs\s*=\s*\(.*\)\s*=>\s*/) +``` + +Your `renderSongs` function should take an `array` parameter. + +```js +assert.match(code, /const\s+renderSongs\s*=\s*\(array/) +``` + +Your `renderSongs` function should be empty. + +```js +assert.match(code, /const\s+renderSongs\s*=\s*\(array\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +

                        freeCodeCamp

                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        + song cover art +
                        +
                        +
                        +

                        +

                        +
                        +
                        + + + + + +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +
                        +

                        Playlist

                        +
                        +
                        +
                        +
                        +
                        +
                          +
                          +
                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md new file mode 100644 index 00000000000..162d0dec075 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420b821b14f25a6b35c3b3.md @@ -0,0 +1,641 @@ +--- +id: 65420b821b14f25a6b35c3b3 +title: Step 12 +challengeType: 0 +dashedName: step-12 +--- + +# --description-- + +Now you should loop through the array. You will call the `renderSongs` function with the songs array inside the `userData` object. For this we will use the `map()` method. + +The `map()` method is used to iterate through an array and return a new array. It's helpful when you want to create a new array based on the values of an existing array. For example: + +```js +const numbers = [1, 2, 3]; +const doubledNumbers = numbers.map((number) => number * 2); // doubledNumbers will be [2, 4, 6] +``` + +Inside the `renderSongs` function, use `const` to create another `songsHTML` function and assign it to `array.map()`. Pass in `song` as the parameter of the `map()` method, a fat arrow, and an empty curly braces. + +# --hints-- + +You should use the `map()` method on `array`. + +```js +assert.match(code, /array.map\(/) +``` + +Your `map()` method should have a `song` parameter in it's callback function. + +```js +assert.match(code, /array.map\(\(?song\)?/) +``` + +The callback function of your `map()` method should use arrow function syntax. + +```js +assert.match(code, /array.map\(\(?song\)?\s*=>\s*\{\s*\}\)/) +``` + +You should assign your `array.map` to a `songsHTML` constant. + +```js +assert.match(code, /const\s+songsHTML\s*=\s*array.map\(\(?song\)?\s*=>\s*\{\s*\}\)/); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                          +
                          +
                          +
                          +
                          +
                          +
                          +

                          freeCodeCamp

                          +
                          +
                          +
                          +
                          +
                          +
                          +
                          + song cover art +
                          +
                          +
                          +

                          +

                          +
                          +
                          + + + + + +
                          +
                          +
                          +
                          +
                          +
                          +
                          +
                          +
                          +
                          +

                          Playlist

                          +
                          +
                          +
                          +
                          +
                          +
                            +
                            +
                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + --fcc-editable-region-- + + --fcc-editable-region-- +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md new file mode 100644 index 00000000000..40cd2b57633 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65420dcfc60580678dad7a92.md @@ -0,0 +1,636 @@ +--- +id: 65420dcfc60580678dad7a92 +title: Step 13 +challengeType: 0 +dashedName: step-13 +--- + +# --description-- + +Inside the `map()`, add a `return` statement with backticks where you will interpolate all the elements responsible to displaying the song details. + +Inside the backticks, create an `li` tag with the id `song-${song.id}` as the first attribute. Also, add the class `playlist-song` as the second attribute. + +# --hints-- + +You should add a `return` statement with an empty pair of backticks. + +```js +assert.match(code, /return\s*`/) +``` + +You should create an `li` tag inside the backticks. + +```js +assert.match(code, /return\s*`\s*\s*<\/li>\s*`;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                            +
                            +
                            +
                            +
                            +
                            +
                            +

                            freeCodeCamp

                            +
                            +
                            +
                            +
                            +
                            +
                            +
                            + song cover art +
                            +
                            +
                            +

                            +

                            +
                            +
                            + + + + + +
                            +
                            +
                            +
                            +
                            +
                            +
                            +
                            +
                            +
                            +

                            Playlist

                            +
                            +
                            +
                            +
                            +
                            +
                              +
                              +
                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array.map((song)=> { +--fcc-editable-region-- + +--fcc-editable-region-- + }) +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md new file mode 100644 index 00000000000..73f2de0fb03 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654210a9eda99477f5697a94.md @@ -0,0 +1,640 @@ +--- +id: 654210a9eda99477f5697a94 +title: Step 14 +challengeType: 0 +dashedName: step-14 +--- + +# --description-- + +Create a `button` element with class `playlist-song-info`. Inside the `button`, add a `span` element with the class `playlist-song-title`, then interpolate `song.title` as the text. + +# --hints-- + +You should create a `button` with the class `playlist-song-info`. + +```js +assert.match(code, /\s*/) +``` + +You should create a `span` element inside your `button` element. + +```js +assert.match(code, /\s*\s*/) +``` + +You should interpolate `song.title` as the content of your `span` element. + +```js +assert.match(code, /\s*\$\{song\.title\}\s*<\/span>\s*<\/button>/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                              +
                              +
                              +
                              +
                              +
                              +
                              +

                              freeCodeCamp

                              +
                              +
                              +
                              +
                              +
                              +
                              +
                              + song cover art +
                              +
                              +
                              +

                              +

                              +
                              +
                              + + + + + +
                              +
                              +
                              +
                              +
                              +
                              +
                              +
                              +
                              +
                              +

                              Playlist

                              +
                              +
                              +
                              +
                              +
                              +
                                +
                                +
                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                              • + --fcc-editable-region-- + + --fcc-editable-region-- + +
                              • + `; + }) +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md new file mode 100644 index 00000000000..6bc262972bf --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654212b82fb5cf872f77148f.md @@ -0,0 +1,648 @@ +--- +id: 654212b82fb5cf872f77148f +title: Step 15 +challengeType: 0 +dashedName: step-15 +--- + +# --description-- + +Inside the `button`, create two more `span` elements. The first span element should have class `playlist-song-artist` and interpolate `song.artist`. The second span element should have class `playlist-song-duration` and interpolate `song.duration`. + +# --hints-- + +You should not modify the existing `button` element and its content. + +```js +assert.match(code, /\s*\$\{song\.title\}\s*<\/span>\s*.*\s*.*\s*<\/button>/) +``` + +You should create a `span` element with the class `playlist-song-artist`. + +```js +assert.match(code, //) +``` + +Your `span` element with the class `playlist-song-artist` should interpolate `song.artist` as its content. + +```js +assert.match(code, /\s*\$\{song\.artist\}\s*<\/span>/) +``` + +You should create a `span` element with the class `playlist-song-duration`. + +```js +assert.match(code, /\s*/) +``` + +Your `span` element with the class `playlist-song-duration` should interpolate `song.duration` as its content. + +```js +assert.match(code, /\s*\$\{song\.duration\}<\/span>/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                +
                                +
                                +
                                +
                                +
                                +
                                +

                                freeCodeCamp

                                +
                                +
                                +
                                +
                                +
                                +
                                +
                                + song cover art +
                                +
                                +
                                +

                                +

                                +
                                +
                                + + + + + +
                                +
                                +
                                +
                                +
                                +
                                +
                                +
                                +
                                +
                                +

                                Playlist

                                +
                                +
                                +
                                +
                                +
                                +
                                  +
                                  +
                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                • + --fcc-editable-region-- + + --fcc-editable-region-- +
                                • + `; + }) +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md new file mode 100644 index 00000000000..a23c321eacb --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654213f2fad2d48f74d6c239.md @@ -0,0 +1,642 @@ +--- +id: 654213f2fad2d48f74d6c239 +title: Step 16 +challengeType: 0 +dashedName: step-16 +--- + +# --description-- + +Create another `button` element with the class `playlist-song-delete` and the `aria-label` attribute set to `Delete` interpolated with `song.title`. For the content of the delete icon, paste in the following SVG: + +```html + +``` + +# --hints-- + +You should create a `button` element with the class `playlist-song-delete` as its first attribute and value. + +```js +assert.match(code, //) +``` + +You should paste in the provided `svg` as the content of your `button` element. + +```js +assert.match(code, /\s*\s*\s*\s*<\/svg>\s*<\/button>\s*/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +

                                  freeCodeCamp

                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  + song cover art +
                                  +
                                  +
                                  +

                                  +

                                  +
                                  +
                                  + + + + + +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                  +

                                  Playlist

                                  +
                                  +
                                  +
                                  +
                                  +
                                  +
                                    +
                                    +
                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                  • + + --fcc-editable-region-- + + --fcc-editable-region-- +
                                  • + `; + }) +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md new file mode 100644 index 00000000000..1f6f2231387 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654215fe7b4a899ddceb3b60.md @@ -0,0 +1,639 @@ +--- +id: 654215fe7b4a899ddceb3b60 +title: Step 17 +challengeType: 0 +dashedName: step-17 +--- + +# --description-- + +Use the `join()` method to combine the `songsHTML` markup into a single string. + +The `join()` method is used to concatenate all the elements of an array into a single string. It takes an optional parameter called `separator` which is used to separate each element of the array. For example: + +```js +const exampleArr = ["This", "is", "a", "sentence"]; +const sentence = exampleArray.join(" "); // Separator takes a space character +console.log(sentence); // Output: "This is a sentence" +``` + +Chain the `join()` method to your `map()` method and pass in an empty string for the separator. + +# --hints-- + +You should add `join("")` to the existing code. + +```js +assert.match(code, /\s*\s*\s*\s*<\/svg>\s*<\/button>\s*<\/li>\s*`;?\s*\}\)\s*.join\(('|")\2\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +

                                    freeCodeCamp

                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    + song cover art +
                                    +
                                    +
                                    +

                                    +

                                    +
                                    +
                                    + + + + + +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                    +

                                    Playlist

                                    +
                                    +
                                    +
                                    +
                                    +
                                    +
                                      +
                                      +
                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + --fcc-editable-region-- + return ` +
                                    • + + +
                                    • + `; + }) + --fcc-editable-region-- +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md new file mode 100644 index 00000000000..364dabdd346 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/654218753c255fabb81f57ca.md @@ -0,0 +1,653 @@ +--- +id: 654218753c255fabb81f57ca +title: Step 19 +challengeType: 0 +dashedName: step-19 +--- + +# --description-- + +Now you need to call the `renderSongs` function and pass in `userData?.songs` in order to finally display the songs in the UI. + +Optional chaining (`?.`) helps prevent errors when accessing nested properties that might be null or undefined. For example: + +```js +const user = { + name: "Quincy", + address: { + city: "San Francisco", + state: "CA", + country: "USA", + }, +}; + +// Accessing nested properties without optional chaining +const state = user.address.state; // CA + +// Accessing a non-existent nested property with optional chaining +const zipCode = user.address?.zipCode; // Returns undefined instead of throwing an error +``` + +Call the `renderSongs` function with the `songs` property of `userData`. This will render the songs in the playlist. + +# --hints-- + +You should call your `renderSongs` function with `userData?.songs`. + +```js +assert.match(code, /renderSongs\(userData\?\.songs\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +

                                      freeCodeCamp

                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      + song cover art +
                                      +
                                      +
                                      +

                                      +

                                      +
                                      +
                                      + + + + + +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                      +

                                      Playlist

                                      +
                                      +
                                      +
                                      +
                                      +
                                      +
                                        +
                                        +
                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                      • + + +
                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; +--fcc-editable-region-- + +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md new file mode 100644 index 00000000000..eaece9b6efa --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65422ba173a18b1bedef1bb6.md @@ -0,0 +1,662 @@ +--- +id: 65422ba173a18b1bedef1bb6 +title: Step 28 +challengeType: 0 +dashedName: step-28 +--- + +# --description-- + +Within the arrow function of the event listener, add an `if` to check if `userData?.currentSong` is `null`. + +Inside the `if` block, call the `playSong()` function with the `id` of the first song in the `userData.songs` array. This will ensure the first song in the playlist is played first. + +# --hints-- + +You should create an `if` statement with the condition `userData?.currentSong === null`. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{/) +``` + +You should call the `playSong` function with `userData?.songs[0].id` inside your `if` block. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +

                                        freeCodeCamp

                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        + song cover art +
                                        +
                                        +
                                        +

                                        +

                                        +
                                        +
                                        + + + + + +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                        +

                                        Playlist

                                        +
                                        +
                                        +
                                        +
                                        +
                                        +
                                          +
                                          +
                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                        • + + +
                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + --fcc-editable-region-- + + --fcc-editable-region-- +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md new file mode 100644 index 00000000000..5d81a703ccf --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552127b2576c2fbc5ecc2ea.md @@ -0,0 +1,672 @@ +--- +id: 6552127b2576c2fbc5ecc2ea +title: Step 29 +challengeType: 0 +dashedName: step-29 +--- + +# --description-- + +Add an `else` block. Inside the `else` block, call the `playSong` function with the `id` of the currently playing song as an argument. + +This ensures that the currently playing song will continue to play when the play button is clicked. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}/) +``` + +You should add an `else` block to your `if` statement. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}\s*else\s*\{/) +``` + +You should call the `playSong` function with `userData?.currentSong.id` in the `else` block of your `if` statement. + + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*playSong\(userData\?\.currentSong\.id\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +

                                          freeCodeCamp

                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          + song cover art +
                                          +
                                          +
                                          +

                                          +

                                          +
                                          +
                                          + + + + + +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          +

                                          Playlist

                                          +
                                          +
                                          +
                                          +
                                          +
                                          +
                                            +
                                            +
                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                          • + + +
                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { +--fcc-editable-region-- + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } + +--fcc-editable-region-- +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md new file mode 100644 index 00000000000..d213f6a0b3f --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521badc7b7470edf952372.md @@ -0,0 +1,680 @@ +--- +id: 65521badc7b7470edf952372 +title: Step 31 +challengeType: 0 +dashedName: step-31 +--- + +# --description-- + +Now you need to work on pausing the currently playing song. + +Define a `pauseSong` function using the `const` keyword and arrow function sysntax. The function should take no parameters. + +# --hints-- + +You should use `const` to create an empty function named `pauseSong`. + +```js +assert.match(code, /const\s+pauseSong\s*=\s*/) +``` + +`pauseSong` should be a function. + +```js +assert.isFunction(pauseSong) +``` + +Your `pauseSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*/) +``` + +Your `pauseSong` function should be empty. + +```js +assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +

                                            freeCodeCamp

                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            + song cover art +
                                            +
                                            +
                                            +

                                            +

                                            +
                                            +
                                            + + + + + +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +

                                            Playlist

                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                              +
                                              +
                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                            • + + +
                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md new file mode 100644 index 00000000000..833085c6231 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65521ec3bb117c195c4f6cb5.md @@ -0,0 +1,668 @@ +--- +id: 65521ec3bb117c195c4f6cb5 +title: Step 32 +challengeType: 0 +dashedName: step-32 +--- + +# --description-- + +To store the current time of the song when it is paused paused, set the `songCurrentTime` of the `userData` object to the `currentTime` of the `audio` variable. + +# --hints-- + +You should not modify the existing `pauseSong` function and its content. + +```js +assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/) +``` + +You should set `userData.songCurrentTime` to `audio.currentTime`. + +```js +assert.match(code, /userData\.songCurrentTime\s*=\s*audio\.currentTime;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +

                                              freeCodeCamp

                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              + song cover art +
                                              +
                                              +
                                              +

                                              +

                                              +
                                              +
                                              + + + + + +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                              +

                                              Playlist

                                              +
                                              +
                                              +
                                              +
                                              +
                                              +
                                                +
                                                +
                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +--fcc-editable-region-- +const pauseSong = () => { + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                              • + + +
                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md new file mode 100644 index 00000000000..dcdbe345dfe --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655220a3fa5c3c200bc8e938.md @@ -0,0 +1,677 @@ +--- +id: 655220a3fa5c3c200bc8e938 +title: Step 33 +challengeType: 0 +dashedName: step-33 +--- + +# --description-- + +Use `classList` and `remove()` method to remove the `.playing` class from the `playButton`, since the song will be paused at this point. + +To finally pause the song, use the `pause()` method on the `audio` variable. `pause()` is a method of the Web Audio API for pausing music files. + +# --hints-- + +You should not modify the existing `pauseSong` function and its content. + +```js +assert.match(code, /const\s+pauseSong\s*=\s*\(\)\s*=>\s*\{\s*userData\.songCurrentTime\s*=\s*audio\.currentTime;?\s*.*\s*.*\s*\};?/) +``` + +You should use the `classList` property and the `remove()` method to remove the class `playing` from the `playButton`. + +```js +assert.match(code, /playButton\.classList\.remove\(('|")playing\1\);?/) +``` + +You should use the `pause()` method on your `audio` variable. + +```js +assert.match(code, /audio\.pause\(\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +

                                                freeCodeCamp

                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                + song cover art +
                                                +
                                                +
                                                +

                                                +

                                                +
                                                +
                                                + + + + + +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +

                                                Playlist

                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                  +
                                                  +
                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +--fcc-editable-region-- +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                • + + +
                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md new file mode 100644 index 00000000000..d708289b5f1 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552303a9a78704f8ff072e9.md @@ -0,0 +1,679 @@ +--- +id: 6552303a9a78704f8ff072e9 +title: Step 34 +challengeType: 0 +dashedName: step-34 +--- + +# --description-- + +You need to hook up the `pauseSong` function to an event listener to make it work. + +Add a `click` event listener to the `pauseButton` element, then pass in `pauseSong` as the second parameter of the event listener. This is the function the event listener will run. + +# --hints-- + +You should call the `addEventListener()` method on your `pauseButton` variable. + +```js +assert.match(code, /pauseButton\.addEventListener\(/) +``` + +Your event listener should listen for a `click` event. + +```js +assert.match(code, /pauseButton\.addEventListener\(('|"|`)click\1/) +``` + +You should pass in `pauseSong` as the second parameter of your `addEventListener` method. + +```js +assert.match(code, /pauseButton\.addEventListener\(('|"|`)click\1,\s*pauseSong\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +

                                                  freeCodeCamp

                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + song cover art +
                                                  +
                                                  +
                                                  +

                                                  +

                                                  +
                                                  +
                                                  + + + + + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +

                                                  Playlist

                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                    +
                                                    +
                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                  • + + +
                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +--fcc-editable-region-- + +--fcc-editable-region-- + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md new file mode 100644 index 00000000000..7dddd761fda --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655235c2e607297f00316650.md @@ -0,0 +1,656 @@ +--- +id: 655235c2e607297f00316650 +title: Step 26 +challengeType: 0 +dashedName: step-26 +--- + +# --description-- + +Next, use the `classList` property and the `add()` method to add the `playing` class to the `playButton` element. This will look for the class `playing` in the CSS file and add it to the `playButton` element. + +To finally play the song, use the `play()` method on the `audio` variable. `play()` is a method from the web audio API for playing an mp3 file. + +# --hints-- + +You should use the `classList` property and the `add` method to add the class `playing` to `playButton`. + +```js +assert.match(code, /playButton\.classList\.add\(("|')playing\1\);?/) +``` + +You should use the `play()` method on the `audio` variable. + +```js +assert.match(code, /audio\.play\(\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +

                                                    freeCodeCamp

                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    + song cover art +
                                                    +
                                                    +
                                                    +

                                                    +

                                                    +
                                                    +
                                                    + + + + + +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +

                                                    Playlist

                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +
                                                      +
                                                      +
                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + + userData.currentSong = song; +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                    • + + +
                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md new file mode 100644 index 00000000000..bca282adc60 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6552385244ccf89b77d6b332.md @@ -0,0 +1,689 @@ +--- +id: 6552385244ccf89b77d6b332 +title: Step 36 +challengeType: 0 +dashedName: step-36 +--- + +# --description-- + +You need to work on playing the next song and the previous song. For this, you will need a `playNextSong` and `playPreviousSong` function. + +Use `const` and arrow syntax to create an empty `playNextSong` function. + +# --hints-- + +You should use `const` to create an empty function named `playNextSong`. + +```js +assert.match(code, /const\s+playNextSong\s*=\s*/) +``` + +`playNextSong` should be a function. + +```js +assert.isFunction(playNextSong) +``` + +Your `playNextSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*/) +``` + +Your `playNextSong` function should be empty. + +```js +assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +

                                                      freeCodeCamp

                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      + song cover art +
                                                      +
                                                      +
                                                      +

                                                      +

                                                      +
                                                      +
                                                      + + + + + +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +

                                                      Playlist

                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +
                                                        +
                                                        +
                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                      • + + +
                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md new file mode 100644 index 00000000000..e001ffe24e0 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655243068222c2c1166b90b0.md @@ -0,0 +1,689 @@ +--- +id: 655243068222c2c1166b90b0 +title: Step 37 +challengeType: 0 +dashedName: step-37 +--- + +# --description-- + +Inside the `playNextSong` function, create an `if` statement to check if the `currentSong` of `userData` is strictly equal to `null`. This will check if there's no current song playing in the `userData` object. + +If the condition is true, call the `playSong` function with the `id` of the first song in the `userData.songs` array as an argument. + +# --hints-- + +You should not modify the existing `playNextSong` function and its content. + +```js +assert.match(code, /const\s+playNextSong\s*=\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*.*\s*\};?/) +``` + +You should create an `if` statement with the condition `userData?.currentSong === null`. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*/) +``` + +You should call the `playSong` function with `userData?.songs[0].id` inside the `if` statement. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +

                                                        freeCodeCamp

                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        + song cover art +
                                                        +
                                                        +
                                                        +

                                                        +

                                                        +
                                                        +
                                                        + + + + + +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +

                                                        Playlist

                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +
                                                          +
                                                          +
                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +--fcc-editable-region-- +const playNextSong = () => { + +} +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                        • + + +
                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md new file mode 100644 index 00000000000..fe1bf864526 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655476e1ff522252fdcce5e4.md @@ -0,0 +1,694 @@ +--- +id: 655476e1ff522252fdcce5e4 +title: Step 38 +challengeType: 0 +dashedName: step-38 +--- + +# --description-- + +Add an `else` block to the `if` statement. Inside the `else` block, call the `getCurrentSongIndex()` function and assign it to a constant named `currentSongIndex`. + +# --hints-- + +You should not modify the existing `if` statement. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}/) +``` + +You should add an `else` to the existing `if` statement. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*/) +``` + +You should set the `currentSongIndex` constant to `getCurrentSongIndex()` inside the `else` block. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*\}/) +``` + + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +

                                                          freeCodeCamp

                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          + song cover art +
                                                          +
                                                          +
                                                          +

                                                          +

                                                          +
                                                          +
                                                          + + + + + +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +

                                                          Playlist

                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                            +
                                                            +
                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + --fcc-editable-region-- + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } + +--fcc-editable-region-- +} + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                          • + + +
                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md new file mode 100644 index 00000000000..59b2f6944c1 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655479aa3e1e0360ae38b7a6.md @@ -0,0 +1,699 @@ +--- +id: 655479aa3e1e0360ae38b7a6 +title: Step 39 +challengeType: 0 +dashedName: step-39 +--- + +# --description-- + +Next, you will need to retrieve the next song in the playlist. For that, you will need to get the index of the current song and then add `1` to it. + +Create a constant called `nextSong` and assign `userData?.songs[currentSongIndex + 1]` to it. + +Lastly, call the `playSong` function and pass in `nextSong.id` as the argument. + +# --hints-- + +You should not modify the existing `if` statement, its `else` block, and content. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/) +``` + +You should assign `userData?.songs[currentSongIndex + 1]` to a `nextSong` constant. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*nextSong\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\];?\s*/) +``` + +You should call the `playSong` function with `nextSong.id`. + +```js +const splitter = code.split('const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong);') + +assert.match(splitter[0], /if\s*\(userData\?\.currentSong\s*===\s*null\)\s*\{\s*playSong\(userData\?\.songs\[0\]\.id\);?\s*\}\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*nextSong\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\];?\s*playSong\(nextSong\.id\);?\s*\}/) +``` + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +

                                                            freeCodeCamp

                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            + song cover art +
                                                            +
                                                            +
                                                            +

                                                            +

                                                            +
                                                            +
                                                            + + + + + +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +

                                                            Playlist

                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                              +
                                                              +
                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { +--fcc-editable-region-- + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + + } +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                            • + + +
                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md new file mode 100644 index 00000000000..1fff918ebea --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65547ee197840478a1b95f4b.md @@ -0,0 +1,695 @@ +--- +id: 65547ee197840478a1b95f4b +title: Step 40 +challengeType: 0 +dashedName: step-40 +--- + +# --description-- + +It's time to hook up the `playNextSong` function to an event listener. + +Add a `click` event listener to the `nextButton` element the pass in `playNextSong` as the second parameter of your event listener. This is the function the event listener will run. + +# --hints-- + +You should call the `addEventListener()` method on your `nextButton` variable. + +```js +assert.match(code, /nextButton\.addEventListener\(/) +``` + +Your event listener should listen for a `click` event. + +```js +assert.match(code, /nextButton\.addEventListener\(('|"|`)click\1/) +``` + +You should pass in `playNextSong` as the second parameter of your `addEventListener` method. + +```js +assert.match(code, /nextButton\.addEventListener\(('|"|`)click\1,\s*playNextSong\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +

                                                              freeCodeCamp

                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              + song cover art +
                                                              +
                                                              +
                                                              +

                                                              +

                                                              +
                                                              +
                                                              + + + + + +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +

                                                              Playlist

                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                                +
                                                                +
                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                              • + + +
                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +--fcc-editable-region-- + +--fcc-editable-region-- + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md new file mode 100644 index 00000000000..c8464429f65 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554815fe2472f8bfdab7642.md @@ -0,0 +1,701 @@ +--- +id: 6554815fe2472f8bfdab7642 +title: Step 41 +challengeType: 0 +dashedName: step-41 +--- + +# --description-- + +Use `const` and arrow syntax to create an empty `playPreviousSong` function. + +# --hints-- + +You should use `const` to create an empty function named `playPreviousSong`. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*/) +``` + +`playPreviousSong` should be a function. + +```js +assert.isFunction(playPreviousSong) +``` + +Your `playPreviousSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*/) +``` + +Your `playPreviousSong` function should be empty. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +

                                                                freeCodeCamp

                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                + song cover art +
                                                                +
                                                                +
                                                                +

                                                                +

                                                                +
                                                                +
                                                                + + + + + +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +

                                                                Playlist

                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                  +
                                                                  +
                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                • + + +
                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md new file mode 100644 index 00000000000..6ebc333a18f --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655482742cc5499726e3f347.md @@ -0,0 +1,713 @@ +--- +id: 655482742cc5499726e3f347 +title: Step 42 +challengeType: 0 +dashedName: step-42 +--- + +# --description-- + +Within the `playPreviousSong` function, add an `if` statement with a condition of `userData?.currentSong === null`. This will check if there is currently no song playing. If there isn't any, exit the function using a `return`. + +Inside the `else` block, create a constant named `currentSongIndex` and assign it `getCurrentSongIndex()`. + +# --hints-- + +You should not alter the existing `playPreviousSong` function and its content. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*/) +``` + +You should have an `if` statement with the condition `userData?.currentSong === null` inside your `playPreviousSong` function. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*/) +``` + +You should have `return` inside the block of your `if` statement. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?/) +``` + +Your `if` statement should have an `else` block. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*/) +``` + +You should call `getCurrentSongIndex` and assign it to `currentSongIndex` inside the `else` block of your `if` statement. + +```js +assert.match(code, /const\s+playPreviousSong\s*=\s*\(\)\s*=>\s*\{\s*if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/) +``` + + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +

                                                                  freeCodeCamp

                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  + song cover art +
                                                                  +
                                                                  +
                                                                  +

                                                                  +

                                                                  +
                                                                  +
                                                                  + + + + + +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +

                                                                  Playlist

                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                  +
                                                                    +
                                                                    +
                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +--fcc-editable-region-- +const playPreviousSong = () => { + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                  • + + +
                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md new file mode 100644 index 00000000000..baa59d09650 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655483ebf0096ba02b2c3d4c.md @@ -0,0 +1,701 @@ +--- +id: 655483ebf0096ba02b2c3d4c +title: Step 43 +challengeType: 0 +dashedName: step-43 +--- + +# --description-- + +To get the previous song, subtract `1` from the `currentSongIndex` of `userData?.songs` and assign it to the constant `previousSong`. After that, call the `playSong` function and pass `previousSong.id` as an argument. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*/) +``` + +You should assign `userData?.songs[currentSongIndex - 1]` to a `previousSong` constant. + +```js +assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*previousSong\s*=\s*userData\?\.songs\[currentSongIndex\s*-\s*1\];?\s*/) +``` + +You should call the `playSong` function with `previousSong.id`. + +```js +assert.match(code, /if\s*\(userData\?.currentSong\s*===\s*null\)\s*\{?\s*return;?\s*\}?\s*else\s*\{\s*const\s*currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*const\s*previousSong\s*=\s*userData\?\.songs\[currentSongIndex\s*-\s*1\];?\s*playSong\(previousSong\.id\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +

                                                                    freeCodeCamp

                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    + song cover art +
                                                                    +
                                                                    +
                                                                    +

                                                                    +

                                                                    +
                                                                    +
                                                                    + + + + + +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +

                                                                    Playlist

                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                      +
                                                                      +
                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { +--fcc-editable-region-- + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + + } +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                    • + + +
                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md new file mode 100644 index 00000000000..5b5a84fba14 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655485321913feabbc5f00f8.md @@ -0,0 +1,705 @@ +--- +id: 655485321913feabbc5f00f8 +title: Step 44 +challengeType: 0 +dashedName: step-44 +--- + +# --description-- + +Add a `click` event listener to the `previousButton` element, then pass in `playPrevious` song as the second parameter. + +# --hints-- + +You should call the `addEventListener()` method on your `previousButton` variable. + +```js +assert.match(code, /previousButton\.addEventListener\(/) +``` + +Your event listener should listen for a `click` event. + +```js +assert.match(code, /previousButton\.addEventListener\(('|"|`)click\1/) +``` + +You should pass in `playPreviousSong` as the second parameter of your `addEventListener` method. + +```js +assert.match(code, /previousButton\.addEventListener\(('|"|`)click\1,\s*playPreviousSong\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +

                                                                      freeCodeCamp

                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      + song cover art +
                                                                      +
                                                                      +
                                                                      +

                                                                      +

                                                                      +
                                                                      +
                                                                      + + + + + +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +

                                                                      Playlist

                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                        +
                                                                        +
                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                      • + + +
                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +--fcc-editable-region-- + +--fcc-editable-region-- + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md new file mode 100644 index 00000000000..3409166e3af --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6554860ea4dfbab2f4786fc8.md @@ -0,0 +1,720 @@ +--- +id: 6554860ea4dfbab2f4786fc8 +title: Step 45 +challengeType: 0 +dashedName: step-45 +--- + +# --description-- + +If you check closely, you'd see the currently playing song is not highlighted in the playlist, so you don't really know which song is playing. You can fix this by creating a function to highlight any song that is being played. + +Using an arrow syntax, create a `highlightCurrentSong` function. Inside the function, use `querySelectorAll` to get the `.playlist-song` element and assign to a `playlistSongElements` constant. + +# --hints-- + +You should use `const` to create a `highlightCurrentSong` function. + +```js +assert.match(code, /const\s+highlightCurrentSong\s*=\s*/) +``` + +`highlightCurrentSong` should be a function. + +```js +assert.isFunction(highlightCurrentSong) +``` + +Your `highlightCurrentSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*/) +``` + +You should create a `playlistSongElements` constant inside your `highlightCurrentSong` function. + +```js +assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*const\s*playlistSongElements\s*=\s*/) +``` + +You should use the `querySelectorAll()` method to select the `.playlist-song` element and assign it to the `playlistSongElements` constant. + +```js +assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*{\s*const\s*playlistSongElements\s*=\s*document\.querySelectorAll\(('|")\.playlist-song\1\);?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +

                                                                        freeCodeCamp

                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        + song cover art +
                                                                        +
                                                                        +
                                                                        +

                                                                        +

                                                                        +
                                                                        +
                                                                        + + + + + +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +

                                                                        Playlist

                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                          +
                                                                          +
                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                        • + + +
                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md new file mode 100644 index 00000000000..ac46246c194 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655487f686aabfc2a10ba887.md @@ -0,0 +1,689 @@ +--- +id: 655487f686aabfc2a10ba887 +title: Step 35 +challengeType: 0 +dashedName: step-35 +--- + +# --description-- + +Before you start working on playing the next and previous song, you need to get the index of each song in the `songs` property of `userData`. Remember this is where you spread in the songs. + +Use an arrow syntax to create a `getCurrentSongIndex` function. Then, using implicit return, use the `indexOf()` method on `userData?.songs`, and pass in `userData.currentSong`. + +Calling this function will get you the index of each song. + +# --hints-- + +You should use `const` to create a `getCurrentSongIndex` function. + +```js +assert.match(code, /const\s+getCurrentSongIndex\s*/) +``` + +Your `getCurrentSongIndex` function should use arrow syntax. + +```js +assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*/) +``` + +Your `getCurrentSongIndex` function should implicitly use the `indexOf()` method on `userData?.songs`. + +```js +assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*userData\?\.songs\.indexOf\(/) +``` + +You should pass in `userData.currentSong` into the `indexOf()`. + +```js +assert.match(code, /const\s+getCurrentSongIndex\s*=\s*\(\)\s*=>\s*userData\?\.songs\.indexOf\(userData\.currentSong\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +

                                                                          freeCodeCamp

                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          + song cover art +
                                                                          +
                                                                          +
                                                                          +

                                                                          +

                                                                          +
                                                                          +
                                                                          + + + + + +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +

                                                                          Playlist

                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                            +
                                                                            +
                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                          • + + +
                                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md new file mode 100644 index 00000000000..9f6a9ba8e66 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65548f747a4cdafd186948d1.md @@ -0,0 +1,712 @@ +--- +id: 65548f747a4cdafd186948d1 +title: Step 46 +challengeType: 0 +dashedName: step-46 +--- + +# --description-- + +You need to get the `id` of the currently playing song. For this, you can use `userData?.currentSong?.id`. + +Use `getElementById()` to get the `id` of the currently playing song, then use template literals to prefix it with `song-`. Assign it to the constant `songToHighlight`. + +# --hints-- + +You should not modify the existing `highlightCurrentSong` function and its content. + +```js +assert.match(code, /const\s+highlightCurrentSong\s*=\s*\(\)\s*=>\s*\s{\s*const\s*playlistSongElements\s*=\s*document\.querySelectorAll\(('|")\.playlist-song\1\);?\s*/) +``` + +You should use `document.getElementById()` and pass in \`song-${userData?.currentSong?.id}\`. + +```js +assert.match(code, /document\.getElementById\(\s*`song-\$\{userData\?\.currentSong\?\.id\}`\s*\);?\s*\};?/) +``` + +You should assign your `getElementById()` to a `songToHighlight` constant. + +```js +assert.match(code, /const\s*songToHighlight\s*=\s*document\.getElementById\(\s*`song-\$\{userData\?\.currentSong\?\.id\}`\s*\);?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +

                                                                            freeCodeCamp

                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            + song cover art +
                                                                            +
                                                                            +
                                                                            +

                                                                            +

                                                                            +
                                                                            +
                                                                            + + + + + +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +

                                                                            Playlist

                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                              +
                                                                              +
                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + + +}; +--fcc-editable-region-- + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                            • + + +
                                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md new file mode 100644 index 00000000000..650845785cd --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655490f55c36900779336988.md @@ -0,0 +1,726 @@ +--- +id: 655490f55c36900779336988 +title: Step 47 +challengeType: 0 +dashedName: step-47 +--- + +# --description-- + +Loop through the `playlistSongElements` with a `forEach` method. + +The `forEach` method is used to loop through an array and perform a function on each element of the array. For example, suppose you have an array of numbers and you want to log each number to the console. + +```js +const numbers = [1, 2, 3, 4, 5]; + +// Using forEach to iterate through the array +numbers.forEach((number) => { + console.log(number); // 1, 2, 3, 4, 5 +}); +``` + +Use the `forEach` method on `playlistSongElements`. Pass in `songEl` as the parameter and use arrow syntax to add in an empty callback. + +# --hints-- + +You should chain `forEach()` to `playlistSongElements`. + +```js +assert.match(code, /playlistSongElements\.forEach\(/) +``` + +Your `forEach()` method should have a `songEl` parameter and use arrow syntax. + +```js +assert.match(code, /playlistSongElements\.forEach\(\(?songEl\)?\s*=>\s*/) +``` + +Your `forEach` should have an empty pair of curly braces. + +```js +assert.match(code, /playlistSongElements\.forEach\(\(?songEl\)?\s*=>\s*\{\s*\}\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +

                                                                              freeCodeCamp

                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              + song cover art +
                                                                              +
                                                                              +
                                                                              +

                                                                              +

                                                                              +
                                                                              +
                                                                              + + + + + +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +

                                                                              Playlist

                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                                +
                                                                                +
                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                              • + + +
                                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md new file mode 100644 index 00000000000..3157fed2381 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655492e6b90c7a198c587943.md @@ -0,0 +1,719 @@ +--- +id: 655492e6b90c7a198c587943 +title: Step 49 +challengeType: 0 +dashedName: step-49 +--- + +# --description-- + +Now you need to add the attribute back to the currently playing song. + +Create an `if` statement with the condition `songToHighlight`. For the statement, use `setAttribute` on `songToHighlight` to pass in `"aria-current"` and `"true"` as the first and second parameters. + +# --hints-- + +You should create an `if` statement with the condition `songToHighlight`. + +```js +assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*/) +``` + +You should use the `setAttribute()` method on `songToHighlight` inside your `if` statement. + +```js +assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*songToHighlight\.setAttribute\(/) +``` + +You should pass in `"aria-current"` and `"true"` as the first and second parameter of your `setAttribute` method. + +```js +assert.match(code, /if\s*\(songToHighlight\)\s*\{?\s*songToHighlight\.setAttribute\(('|")aria-current\1,\s*\1true\1\)\s*;?\s*\}?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +

                                                                                freeCodeCamp

                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                + song cover art +
                                                                                +
                                                                                +
                                                                                +

                                                                                +

                                                                                +
                                                                                +
                                                                                + + + + + +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +

                                                                                Playlist

                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                  +
                                                                                  +
                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                • + + +
                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md new file mode 100644 index 00000000000..dda63a85421 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655494d5a15d6a2567e1ea60.md @@ -0,0 +1,708 @@ +--- +id: 655494d5a15d6a2567e1ea60 +title: Step 50 +challengeType: 0 +dashedName: step-50 +--- + +# --description-- + +Inside the `playSong` function, call the `highlightCurrentSong` function. + +After that, play around with the control buttons to see how the `highlightCurrentSong` function works. + +# --hints-- + +You should call the `highlightCurrentSong` function. + +```js +assert.match(code, /highlightCurrentSong\(\)/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +

                                                                                  freeCodeCamp

                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  + song cover art +
                                                                                  +
                                                                                  +
                                                                                  +

                                                                                  +

                                                                                  +
                                                                                  +
                                                                                  + + + + + +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +

                                                                                  Playlist

                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                  +
                                                                                    +
                                                                                    +
                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + +--fcc-editable-region-- + +--fcc-editable-region-- + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                  • + + +
                                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md new file mode 100644 index 00000000000..0a7eb00a57c --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655495a6bd96e42bc3baa795.md @@ -0,0 +1,726 @@ +--- +id: 655495a6bd96e42bc3baa795 +title: Step 51 +challengeType: 0 +dashedName: step-51 +--- + +# --description-- + +Next, you need to display the current song title and artist in the player display. Use `const` and arrow syntax to create an empty `setPlayerDisplay` function. + +# --hints-- + +You should use `const` to create an empty function named `setPlayerDisplay`. + +```js +assert.match(code, /const\s+setPlayerDisplay\s*=\s*/) +``` + +`setPlayerDisplay` should be a function. + +```js +assert.isFunction(setPlayerDisplay) +``` + +Your `setPlayerDisplay` function should use an arrow syntax. + +```js +assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*/) +``` + +Your `setPlayerDisplay` function should be empty. + +```js +assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +

                                                                                    freeCodeCamp

                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    + song cover art +
                                                                                    +
                                                                                    +
                                                                                    +

                                                                                    +

                                                                                    +
                                                                                    +
                                                                                    + + + + + +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +

                                                                                    Playlist

                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                    +
                                                                                      +
                                                                                      +
                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                    • + + +
                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md new file mode 100644 index 00000000000..5cf3885dc79 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d17af9ff06a14d399f6d.md @@ -0,0 +1,736 @@ +--- +id: 6555d17af9ff06a14d399f6d +title: Step 52 +challengeType: 0 +dashedName: step-52 +--- + +# --description-- + +Inside the function, obtain refrences to the HTML elements responsible for displaying the song title and artist. + +Access the `#player-song-title` and `#player-song-artist` elements with the `getElementById()` method. Assign them to variables `playingSong` and `songArtist` respectively. + +# --hints-- + +You should not modify the existing `setPlayerDisplay` function and its content. + +```js +assert.match(code, /const\s+setPlayerDisplay\s*=\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*\};?/) +``` + +You should use `document.getElementById()` to get the `#player-song-title` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)player\-song\-title\1\);?/); +``` + +You should assign the `#player-song-title` element to the variable `playingSong`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+playingSong\s*\=\s*document\.getElementById\(\s*('|"|`)player\-song\-title\1\);?/); +``` + +You should use `document.getElementById()` to get the `#player-song-artist` element. + +```js +assert.match(code, /document\.getElementById\(\s*('|"|`)player\-song\-artist\1\);?/); +``` + +You should assign the `#player-song-artist` element to the variable `songArtist`. Don't forget to use `const` to declare the variable. + +```js +assert.match(code, /const\s+songArtist\s*\=\s*document\.getElementById\(\s*('|"|`)player\-song\-artist\1\);?/); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +

                                                                                      freeCodeCamp

                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      + song cover art +
                                                                                      +
                                                                                      +
                                                                                      +

                                                                                      +

                                                                                      +
                                                                                      +
                                                                                      + + + + + +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +

                                                                                      Playlist

                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                      +
                                                                                        +
                                                                                        +
                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- +const setPlayerDisplay = () => { + +}; +--fcc-editable-region-- + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                      • + + +
                                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md new file mode 100644 index 00000000000..edc82a2d3cf --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d458687cb3b357834df9.md @@ -0,0 +1,730 @@ +--- +id: 6555d458687cb3b357834df9 +title: Step 53 +challengeType: 0 +dashedName: step-53 +--- + +# --description-- + +Access the `userData?.currentSong?.title` and `userData?.currentSong?.artist` properties and assign them to a `currentTitle` and `currentArtist` variables respectively. + +# --hints-- + +You should access the `title` of `currentSong` from the `userData` object. Don't forget to use optional chaining. + +```js +assert.match(code, /userData\?\.currentSong\?\.title;?/) +``` + +You should assign the `title` of the `currentSong` to a `currentTitle` constant. + +```js +assert.match(code, /const\s+currentTitle\s*=\s*userData\?\.currentSong\?\.title;?/) +``` + +You should access the `artist` of `currentSong` from the `userData` object. Don't forget to use optional chaining. + +```js +assert.match(code, /userData\?\.currentSong\?\.artist;?/) +``` + +You should assign the `artist` of the `currentSong` to a `currentArtist` constant. + +```js +assert.match(code, /const\s+currentArtist\s*=\s*userData\?\.currentSong\?\.artist;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +

                                                                                        freeCodeCamp

                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        + song cover art +
                                                                                        +
                                                                                        +
                                                                                        +

                                                                                        +

                                                                                        +
                                                                                        +
                                                                                        + + + + + +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +

                                                                                        Playlist

                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                        +
                                                                                          +
                                                                                          +
                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                        • + + +
                                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md new file mode 100644 index 00000000000..8f42b463f0c --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d729c9bfd7c3195f1948.md @@ -0,0 +1,745 @@ +--- +id: 6555d729c9bfd7c3195f1948 +title: Step 54 +challengeType: 0 +dashedName: step-54 +--- + +# --description-- + +`textContent` sets the text of a node and allows you to set or retrieve the text content of an HTML element. + +```html +
                                                                                          This is some text content
                                                                                          +``` + +```js +const element = document.getElementById('example'); +console.log(element.textContent); // Output: This is some text content +``` + +Use a `ternary` operator to check if `currentTitle` is truthy. If so, implicitly return `currentTitle` otherwise implicitly return an empty string. Assign this result to `playingSong.textContent`. + +Then, use a `ternary` operator to check if `currentArtist` is truthy. If so, implicitly return `currentArtist` otherwise implicitly return an empty string. Assign this result to `songArtist.textContent`. + +# --hints-- + +You should chain the `textContent` property to `playingSong`. + +```js +assert.match(code, /playingSong.textContent\s*/) +``` + +You should use the `ternary` operator to set the `textContent` property of `playingSong` to `currentTitle` or `""`. + +```js +assert.match(code, /playingSong.textContent\s*=\s*currentTitle\s*\?\s*currentTitle\s*:\s*('|")\1;?/) +``` + +You should chain the `textContent` property to `songArtist`. + +```js +assert.match(code, /songArtist.textContent\s*/) +``` + +You should use the `ternary` operator to set the `textContent` property of `songArtist` to `currentArtist` or `""`. + +```js +assert.match(code, /songArtist.textContent\s*=\s*currentArtist\s*\?\s*currentArtist\s*:\s*('|")\1;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +

                                                                                          freeCodeCamp

                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          + song cover art +
                                                                                          +
                                                                                          +
                                                                                          +

                                                                                          +

                                                                                          +
                                                                                          +
                                                                                          + + + + + +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +

                                                                                          Playlist

                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                          +
                                                                                            +
                                                                                            +
                                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                          • + + +
                                                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md new file mode 100644 index 00000000000..31638b97df3 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d7e384056dc9c581fadf.md @@ -0,0 +1,719 @@ +--- +id: 6555d7e384056dc9c581fadf +title: Step 55 +challengeType: 0 +dashedName: step-55 +--- + +# --description-- + +To ensure the player's display updates whenever a new song begins playing, call the `setPlayerDisplay()` function within the `playSong()` function. + +Now you should see the song title and the artist show up in the display. + +# --hints-- + +You should call the `setPlayerDisplay` function inside your `playSong` function. + +```js +assert.match(code, /setPlayerDisplay\(\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +

                                                                                            freeCodeCamp

                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            + song cover art +
                                                                                            +
                                                                                            +
                                                                                            +

                                                                                            +

                                                                                            +
                                                                                            +
                                                                                            + + + + + +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +

                                                                                            Playlist

                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                            +
                                                                                              +
                                                                                              +
                                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); +--fcc-editable-region-- + +--fcc-editable-region-- + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                            • + + +
                                                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md new file mode 100644 index 00000000000..dddff83c305 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555d8faed60b9d3e4a6cefb.md @@ -0,0 +1,739 @@ +--- +id: 6555d8faed60b9d3e4a6cefb +title: Step 56 +challengeType: 0 +dashedName: step-56 +--- + +# --description-- + +Use `const` and arrow syntax to define a function called `setPlayButtonAccessibleText`. + +This function will set the `aria-label` attribute to the current song, or to the first song in the playlist. And if the playlist is empty, it sets the `aria-label` to `"Play"`. + +# --hints-- + +You should use `const` to create an empty function named `setPlayButtonAccessibleText`. + +```js +assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*/) +``` + +`setPlayButtonAccessibleText` should be a function. + +```js +assert.isFunction(setPlayButtonAccessibleText) +``` + +Your `setPlayButtonAccessibleText` function should use an arrow syntax. + +```js +assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*/) +``` + +Your `setPlayButtonAccessibleText` function should be empty. + +```js +assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +

                                                                                              freeCodeCamp

                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              + song cover art +
                                                                                              +
                                                                                              +
                                                                                              +

                                                                                              +

                                                                                              +
                                                                                              +
                                                                                              + + + + + +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +

                                                                                              Playlist

                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                              +
                                                                                                +
                                                                                                +
                                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                              • + + +
                                                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md new file mode 100644 index 00000000000..3807073d5cb --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555dd138e70cae6b546966d.md @@ -0,0 +1,735 @@ +--- +id: 6555dd138e70cae6b546966d +title: Step 57 +challengeType: 0 +dashedName: step-57 +--- + +# --description-- + +You need to get the currently playing song or the first song in the playlist. To do that, create a `song` constant and set it to the current song of `userData`, **or** the first song in the `userData?.songs` array. + +Don't forget to use optional chaining. + +# --hints-- + +You should not modify the existing `setPlayButtonAccessibleText` and its content. + +```js +assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/) +``` + +You should access `userData?.currentSong` or `userData?.songs[0]`. + +```js +assert.match(code, /userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?/) +``` + +You should assign `userData?.currentSong || userData?.songs[0]` to a `song` constant. + +```js +assert.match(code, /const\s+song\s*=\s*userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +

                                                                                                freeCodeCamp

                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                + song cover art +
                                                                                                +
                                                                                                +
                                                                                                +

                                                                                                +

                                                                                                +
                                                                                                +
                                                                                                + + + + + +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +

                                                                                                Playlist

                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                +
                                                                                                  +
                                                                                                  +
                                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                • + + +
                                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +--fcc-editable-region-- +const setPlayButtonAccessibleText = () => { + +}; +--fcc-editable-region-- + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md new file mode 100644 index 00000000000..fbd83bd56bc --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555de565387a2efe90a6ccc.md @@ -0,0 +1,742 @@ +--- +id: 6555de565387a2efe90a6ccc +title: Step 58 +challengeType: 0 +dashedName: step-58 +--- + +# --description-- + +Use the `setAttribute` method on the `playButton` element to set an attribute named `aria-label`. For the value, use a `ternary` to set `song?.title` to `Play ${song.title}` or `"Play"` if there's no `song.title` available. + +Don't forget you need template interpolation here, so you need to use backticks. + +# --hints-- + +You should not modify the existing `setPlayButtonAccessibleText` function and its content. + +```js +assert.match(code, /const\s+setPlayButtonAccessibleText\s*=\s*\(\)\s*=>\s*\{\s*const\s+song\s*=\s*userData\?\.currentSong\s*\|\|\s*userData\?\.songs\[0\];?\s*.*\s*.*\s*.*\s*.*\s*\};?/) +``` + +You should use the `setAttribute()` method on `playButton`. + +```js +assert.match(code, /playButton\.setAttribute\(\s*/) +``` + +`"aria-label"` should be the first value of your `setAttribute()` method. + +```js +assert.match(code, /playButton\.setAttribute\(\s*('|")aria-label\1/) +``` + +Your `setAttribute` method should have `song?.title ? \`Play ${song.title}\` : "Play"` as the second argument. + +```js +assert.match(code, /playButton\.setAttribute\(\s*('|")aria-label\1,\s*song\?\.title\s*\?\s*`Play\s*\$\{song\.title\}`\s*:\s*\1Play\1\s*\);?\s*/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +

                                                                                                  freeCodeCamp

                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  + song cover art +
                                                                                                  +
                                                                                                  +
                                                                                                  +

                                                                                                  +

                                                                                                  +
                                                                                                  +
                                                                                                  + + + + + +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +

                                                                                                  Playlist

                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                  +
                                                                                                    +
                                                                                                    +
                                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                  • + + +
                                                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +--fcc-editable-region-- +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + +}; +--fcc-editable-region-- + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md new file mode 100644 index 00000000000..574e3466950 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e04aeb225bfbae237344.md @@ -0,0 +1,727 @@ +--- +id: 6555e04aeb225bfbae237344 +title: Step 59 +challengeType: 0 +dashedName: step-59 +--- + +# --description-- + +Now, call the `setPlayButtonAccessibleText` function inside the `playSong` function. + +# --hints-- + +You should call the `setPlayButtonAccessibleText` inside your `playSong` function. + +```js +assert.match(code, /setPlayButtonAccessibleText\(\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +

                                                                                                    freeCodeCamp

                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    + song cover art +
                                                                                                    +
                                                                                                    +
                                                                                                    +

                                                                                                    +

                                                                                                    +
                                                                                                    +
                                                                                                    + + + + + +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +

                                                                                                    Playlist

                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                    +
                                                                                                      +
                                                                                                      +
                                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); +--fcc-editable-region-- + +--fcc-editable-region-- + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                    • + + +
                                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md new file mode 100644 index 00000000000..e5d3ad733e7 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e0bfe4d69904410f7cd3.md @@ -0,0 +1,749 @@ +--- +id: 6555e0bfe4d69904410f7cd3 +title: Step 60 +challengeType: 0 +dashedName: step-60 +--- + +# --description-- + +Using `const` and arrow syntax to create an empty function called `shuffle`. + +This function is responsible for shuffling the songs in the playlist and performing necessary state management updates after the shuffling. + +# --hints-- + +You should use `const` to create an empty function named `shuffle`. + +```js +assert.match(code, /const\s+shuffle\s*=\s*/) +``` + +`shuffle` should be a function. + +```js +assert.isFunction(shuffle) +``` + +Your `shuffle` function should use an arrow syntax and should not take a parameter. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*/) +``` + +Your `shuffle` function should be empty. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +

                                                                                                      freeCodeCamp

                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      + song cover art +
                                                                                                      +
                                                                                                      +
                                                                                                      +

                                                                                                      +

                                                                                                      +
                                                                                                      +
                                                                                                      + + + + + +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +

                                                                                                      Playlist

                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                      +
                                                                                                        +
                                                                                                        +
                                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                      • + + +
                                                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md new file mode 100644 index 00000000000..cd46fb8acc9 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e39a5f4c6f138c7d9405.md @@ -0,0 +1,767 @@ +--- +id: 6555e39a5f4c6f138c7d9405 +title: Step 61 +challengeType: 0 +dashedName: step-61 +--- + +# --description-- + +The `sort()` method converts elements of an array into strings and sorts them based on their `UTF-16` code units values. + +```js +const numbers = [4, 2, 5, 100, 1, 3]; + +numbers.sort(); +console.log(numbers); // Output: [1, 100, 2, 3, 4, 5] +``` + +You can see `100` comes right after 1, which is not supposed to happen. This is a default behavior of the `sort()` method you can fix by passing in a callback this way: + +```js +const numbers = [4, 2, 5, 100, 1, 3]; + +numbers.sort((a, b) => a - b); +console.log(numbers); // Output: [1, 2, 3, 4, 5, 100] +``` + +Use the `sort()` method on the `userData?.songs` array. For the callback, introduce `Math.random()`, and subtract `0.5`. + +# --hints-- + +You should not modify the existing `shuffle` function. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*.*\s*\};?/) +``` + +You should use the `sort()` method on `userData?.songs`. + +```js +assert.match(code, /userData\?\.songs\.sort\(/) +``` + +Your `sort()` method should have a callback function that uses arrow syntax. + +```js +assert.match(code, /userData\?\.songs\.sort\(\(\)\s*=>\s*/) +``` + +The callback of your `sort()` method should implicitly return `Math.random() - 0.5` + +```js +assert.match(code, /userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +

                                                                                                        freeCodeCamp

                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        + song cover art +
                                                                                                        +
                                                                                                        +
                                                                                                        +

                                                                                                        +

                                                                                                        +
                                                                                                        +
                                                                                                        + + + + + +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +

                                                                                                        Playlist

                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                        +
                                                                                                          +
                                                                                                          +
                                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- +const shuffle = () => { + +}; +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                        • + + +
                                                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md new file mode 100644 index 00000000000..e1e4577811f --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e57d3e6d9d221c4735be.md @@ -0,0 +1,740 @@ +--- +id: 6555e57d3e6d9d221c4735be +title: Step 62 +challengeType: 0 +dashedName: step-62 +--- + +# --description-- + +When the shuffle button is pressed, you want to set the `currentSong` to nothing and the `songCurrentTime` to `0`. + +Set `userData.currentSong` to `null` and `userData.songCurrentTime` to `0`. + +# --hints-- + +You should set `userData.currentSong` to `null`. + +```js +assert.match(code, /userData\.currentSong\s*=\s*null;?/) +``` + +You should set `userData.songCurrentTime` to `0`. + +```js +assert.match(code, /userData\.songCurrentTime\s*=\s*0;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +

                                                                                                          freeCodeCamp

                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          + song cover art +
                                                                                                          +
                                                                                                          +
                                                                                                          +

                                                                                                          +

                                                                                                          +
                                                                                                          +
                                                                                                          + + + + + +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +

                                                                                                          Playlist

                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                          +
                                                                                                            +
                                                                                                            +
                                                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                          • + + +
                                                                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md new file mode 100644 index 00000000000..1691603f42b --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e6cec786da2aadc11ea0.md @@ -0,0 +1,761 @@ +--- +id: 6555e6cec786da2aadc11ea0 +title: Step 63 +challengeType: 0 +dashedName: step-63 +--- + +# --description-- + +You should also re-render the songs, pause the currently playing song, set the player display, and set the play button accessible text again. + +Call the `renderSongs` function and pass in `userData?.songs` as an argument. Also, call the `pauseSong`, `setPlayerDisplay`, and `setPlayButtonAccessibleText` functions. + +# --hints-- + +You should not modify the existing `shuffle` function and its content. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*.*\s*.*\s*.*\s*.*\s*\};?/) +``` + +You should call the `renderSongs` function with `userData?.songs`. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*.*\s*\};?/) +``` + +You should call the `pauseSong` function. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*.*\s*.*\s*\};?/) +``` + +You should call the `setPlayerDisplay` function. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*.*\s*\};?/) +``` + +You should call the `setPlayButtonAccessibleText` function. + +```js +assert.match(code, /const\s+shuffle\s*=\s*\(\)\s*=>\s*\{\s*userData\?\.songs\.sort\(\(\)\s*=>\s*Math\.random\(\)\s*-\s*0\.5\);?\s*userData\.currentSong\s*=\s*null;\s*userData\.songCurrentTime\s*=\s*0;?\s*renderSongs\(userData\?\.songs\);?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*setPlayButtonAccessibleText\(\);?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +

                                                                                                            freeCodeCamp

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            + song cover art +
                                                                                                            +
                                                                                                            +
                                                                                                            +

                                                                                                            +

                                                                                                            +
                                                                                                            +
                                                                                                            + + + + + +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +

                                                                                                            Playlist

                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                            +
                                                                                                              +
                                                                                                              +
                                                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +--fcc-editable-region-- +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + +}; +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                            • + + +
                                                                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md new file mode 100644 index 00000000000..c0c08fbbb0c --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e7acdbae972d3e8e0f5b.md @@ -0,0 +1,754 @@ +--- +id: 6555e7acdbae972d3e8e0f5b +title: Step 64 +challengeType: 0 +dashedName: step-64 +--- + +# --description-- + +Add a `click` event listener to the `shuffleButton` element. For the function to run, pass in the `shuffle` function. + +**Note**: You don't need a callback inside this particular event listener. You also don't need to call the `shuffle` function, just pass in its identifier. + +# --hints-- + +You should chain the `addEventListener()` method to `shuffleButton`. + +```js +assert.match(code, /shuffleButton\.addEventListener\(/) +``` + +Your event listener should listen for a `click` event. + +```js +assert.match(code, /shuffleButton\.addEventListener\(('|")click\1/) +``` + +You should pass in `shuffle` as the second value of your `click` event listener. + +```js +assert.match(code, /shuffleButton\.addEventListener\(('|")click\1,\s*shuffle\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +

                                                                                                              freeCodeCamp

                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              + song cover art +
                                                                                                              +
                                                                                                              +
                                                                                                              +

                                                                                                              +

                                                                                                              +
                                                                                                              +
                                                                                                              + + + + + +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +

                                                                                                              Playlist

                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                              +
                                                                                                                +
                                                                                                                +
                                                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                              • + + +
                                                                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +--fcc-editable-region-- + +--fcc-editable-region-- + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md new file mode 100644 index 00000000000..43622792c67 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555e9197bf1d7416bdd76e0.md @@ -0,0 +1,768 @@ +--- +id: 6555e9197bf1d7416bdd76e0 +title: Step 65 +challengeType: 0 +dashedName: step-65 +--- + +# --description-- + +It's time to implement a delete functionality for the playlist. This would manage the removal of a song from the playlist, handle other related actions when a song is deleted, and create a `Reset Playlist` button. + +Use `const` and arrow syntax to create an empty `deleteSong` function and pass in `id` as a parameter. + +# --hints-- + +You should use `const` to create an empty function named `deleteSong`. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*/) +``` + +`deleteSong` should be a function. + +```js +assert.isFunction(deleteSong) +``` + +Your `deleteSong` function should use an arrow syntax. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(.*\)\s*=>\s*/) +``` + +Your `deleteSong` function should take an `id` parameter. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id/) +``` + +Your `deleteSong` function should be empty. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\n?\s*?\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +

                                                                                                                freeCodeCamp

                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                + song cover art +
                                                                                                                +
                                                                                                                +
                                                                                                                +

                                                                                                                +

                                                                                                                +
                                                                                                                +
                                                                                                                + + + + + +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +

                                                                                                                Playlist

                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +--fcc-editable-region-- + +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                • + + +
                                                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md new file mode 100644 index 00000000000..9d37dbcdaa1 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6555ebf07ec610585a626f72.md @@ -0,0 +1,779 @@ +--- +id: 6555ebf07ec610585a626f72 +title: Step 66 +challengeType: 0 +dashedName: step-66 +--- + +# --description-- + +Use the `filter()` method to remove the song object that matches the `id` parameter from the `userData.songs` array. + +The `filter` method keeps only the elements of an array that satisfy the callback function passed to it: + +```js +const numArr = [1, 10, 8, 3, 4, 5] +const numsGreaterThanThree = numArr.filter((num) => num > 3); + +console.log(numsGreaterThanThree) // Output: [10, 8, 4, 5] +``` + +Use the `filter()` method on `userData?.songs`. Pass in `song` as the parameter of the arrow function callback and use implicit return to check if `song.id` is strictly not equal to `id`. Assign all of that to the userData.songs. + +# --hints-- + +You should not modify the existing `deleteSong` function. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*.*\s*\};?/) +``` + +You should use the `filter()` method on `userData?.songs`. + +```js +assert.match(code, /userData\?\.songs\.filter\(/) +``` + +The callback function of your `filter()` method should use arrow syntax and have a `song` parameter. + +```js +assert.match(code, /userData\?\.songs\.filter\(\(?song\)?\s*=>\s*/) +``` + +Your filter method should implicitly return `song.id !== id`. + +```js +assert.match(code, /userData\?\.songs\.filter\(\(?song\)?\s*=>\s*song\.id\s*!==\s*id\);?/) +``` + +You should assign the `filter()` method you used on `userData?.songs` to `userData.songs`. + +```js +assert.match(code, /userData\.songs\s*=\s*userData\?\.songs\.filter\(\(?song\)?\s*=>\s*song\.id\s*!==\s*id\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +

                                                                                                                  freeCodeCamp

                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  + song cover art +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +

                                                                                                                  +

                                                                                                                  +
                                                                                                                  +
                                                                                                                  + + + + + +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +

                                                                                                                  Playlist

                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                  +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +--fcc-editable-region-- +const deleteSong = (id) => { + +}; +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                  • + + +
                                                                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md new file mode 100644 index 00000000000..a56133694f9 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65571e742fbf4532d8f98e90.md @@ -0,0 +1,767 @@ +--- +id: 65571e742fbf4532d8f98e90 +title: Step 67 +challengeType: 0 +dashedName: step-67 +--- + +# --description-- + +You need to re-render the songs, highlight it and set the play button's accessible text since the song list will change. + +Call the `renderSongs` function and pass in the `userData?.songs` array as an argument, this displays the modified playlist. + +After that, call the `highlightCurrentSong` function to highlight the current song if there is any also and the `setPlayButtonAccessibleText` function to update the play button's accessible text. + +# --hints-- + +You should not modify the existing `deleteSong` function and its content. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*.*\s*.*\s*.*\s*\};?/) +``` + +You should call the `renderSongs` function with `userData?.songs`. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*\};?/) +``` + +You should call the `highlightCurrentSong` function. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*highlightCurrentSong\(\);?\s*.*\s*\};?/) +``` + +You should call the `setPlayButtonAccessibleText` function. + +```js +assert.match(code, /const\s+deleteSong\s*=\s*\(id\)\s*=>\s*\{\s*userData\.songs\s*=\s*userData\?\.songs\.filter\(\(song\)\s*=>\s*song\.id\s*!==\s*id\);?\s*renderSongs\(userData\?\.songs\);?\s*highlightCurrentSong\(\);?\s*setPlayButtonAccessibleText\(\);?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +

                                                                                                                    freeCodeCamp

                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    + song cover art +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +

                                                                                                                    +

                                                                                                                    +
                                                                                                                    +
                                                                                                                    + + + + + +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +

                                                                                                                    Playlist

                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                    +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +--fcc-editable-region-- +const deleteSong = (id) => { + userData.songs = userData?.songs.filter((song) => song.id !== id); + +}; +--fcc-editable-region-- + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                    • + + +
                                                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md new file mode 100644 index 00000000000..499c67027ae --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655720534347cb3f31cdfb3d.md @@ -0,0 +1,752 @@ +--- +id: 655720534347cb3f31cdfb3d +title: Step 68 +challengeType: 0 +dashedName: step-68 +--- + +# --description-- + +Before deleting a song, you need to check if the song is currently playing. If it is, you need to pause the song and play the next song in the playlist. + +Use an `if` statement to check if the `userData?.currentSong?.id` is equal to the `id` of the song you want to delete. + +# --hints-- + +You should create an empty `if` statement with the condition `userData?.currentSong?.id === id`. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +

                                                                                                                      freeCodeCamp

                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      + song cover art +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +

                                                                                                                      +

                                                                                                                      +
                                                                                                                      +
                                                                                                                      + + + + + +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +

                                                                                                                      Playlist

                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                      +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { +--fcc-editable-region-- + +--fcc-editable-region-- + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                      • + + +
                                                                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md new file mode 100644 index 00000000000..bfa2283147d --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572399a8e16d50bc2c1ff3.md @@ -0,0 +1,777 @@ +--- +id: 65572399a8e16d50bc2c1ff3 +title: Step 69 +challengeType: 0 +dashedName: step-69 +--- + +# --description-- + +If there is a match then set `userData.currentSong` to `null` and `userData.songCurrentTime` to `0`. + +Afther that, call the `pauseSong()` function to stop the playback and the `setPlayerDisplay()` function to update the player display. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*.*\s*.*\s*.*\s*.*\s*\}/) +``` + +You should set `userData.currentSong` to `null`. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*.*\s*.*\s*.*\s*\}/) +``` + +You should set `userData.songCurrentTime` to `0`. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*.*\s*.*\s*\}/) +``` + +You should call the `pauseSong` function. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*pauseSong\(\);?\s*.*\s*\}/) +``` + +You should call the `setPlayerDisplay` function. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\?\.id\s*===\s*id\)\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*pauseSong\(\);?\s*setPlayerDisplay\(\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +

                                                                                                                        freeCodeCamp

                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        + song cover art +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +

                                                                                                                        +

                                                                                                                        +
                                                                                                                        +
                                                                                                                        + + + + + +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +

                                                                                                                        Playlist

                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                        +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { +--fcc-editable-region-- + if (userData?.currentSong?.id === id) { + + } +--fcc-editable-region-- + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                        • + + +
                                                                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md new file mode 100644 index 00000000000..35b135022ff --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655724bac464795a0ad91082.md @@ -0,0 +1,760 @@ +--- +id: 655724bac464795a0ad91082 +title: Step 71 +challengeType: 0 +dashedName: step-71 +--- + +# --description-- + +Next, you need to check if the playlist is empty. If it is, you should reset the `userData` object to its original state. + +Use an `if` statement to check if the `userData.songs` has a length of `0`. + +# --hints-- + +You should create an empty `if` statement with the condition `userData.songs.length === 0` + +```js +assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +

                                                                                                                          freeCodeCamp

                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          + song cover art +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +

                                                                                                                          +

                                                                                                                          +
                                                                                                                          +
                                                                                                                          + + + + + +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +

                                                                                                                          Playlist

                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                          +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +--fcc-editable-region-- + +--fcc-editable-region-- + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                          • + + +
                                                                                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md new file mode 100644 index 00000000000..22f07507dab --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655727b2e1e49d6adf584442.md @@ -0,0 +1,791 @@ +--- +id: 655727b2e1e49d6adf584442 +title: Step 72 +challengeType: 0 +dashedName: step-72 +--- + +# --description-- + +If the playlist is empty, you need to create a `resetButton` element and a text for it. This button will only show up if the playlist is empty. + +`createElement()` is a DOM method you can use to dynamically create an element using JavaScript. To use `createElement()`, you call it, then pass in the tag name as a string: + +```js +// syntax +document.createElement(tagName) + +// example +document.createElement('div') +``` + +You can also assign it to a variable: + +```js +const divElement = document.createElement('div') +``` + +Inside your `if` statement, declare a `resetButton` constant, then use `createElement()` to create a `button`. + + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*.*\s*\}/) +``` + +You should use the `createElement` method to create a `button`. + +```js +assert.match(code, /document\.createElement\(('|")button\1\);?/) +``` + +You should assign your newly created `button` element to a `resetButton` constant. + +```js +assert.match(code, /const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +

                                                                                                                            freeCodeCamp

                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            + song cover art +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +

                                                                                                                            +

                                                                                                                            +
                                                                                                                            +
                                                                                                                            + + + + + +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +

                                                                                                                            Playlist

                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                            +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +--fcc-editable-region-- + if (userData.songs.length === 0) { + + } +--fcc-editable-region-- + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                            • + + +
                                                                                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md new file mode 100644 index 00000000000..ae325b157ee --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655729e68e49b277a6b448bd.md @@ -0,0 +1,779 @@ +--- +id: 655729e68e49b277a6b448bd +title: Step 74 +challengeType: 0 +dashedName: step-74 +--- + +# --description-- + +Now that you've created the `resetButton`, you need to assign it an `id` and `aria-label` attributes. JavaScript provides the `id` and `ariaLabel` properties you need to use for this. + +For example, `element.id` would set an `id` attribute, and `element.ariaLabel` would set an `aria-label` attribute. Both of them accept their values as a string. + +Set the `id` attribute of `resetButton` to `reset` and its `aria-label` attribute to `Reset playlist`. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?\s*.*\s*.*\s*.*\s*\}/) +``` + +You should use `resetButton.id` to create an `id` attribute named `reset` for the `resetButton`. + +```js +assert.match(code, /resetButton\.id\s*=\s*('|")reset\1/) +``` + +You should use `resetButton.ariaLabel` to create an `aria-label` attribute named `Reset playlist` for the `resetButton`. + +```js +assert.match(code, /resetButton\.ariaLabel\s*=\s*('|")Reset\s+playlist\1;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +

                                                                                                                              freeCodeCamp

                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              + song cover art +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +

                                                                                                                              +

                                                                                                                              +
                                                                                                                              +
                                                                                                                              + + + + + +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +

                                                                                                                              Playlist

                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                              +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +--fcc-editable-region-- + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + + } +--fcc-editable-region-- + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                              • + + +
                                                                                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md new file mode 100644 index 00000000000..6dd0fe3278e --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572bb34a7e488224b937fc.md @@ -0,0 +1,795 @@ +--- +id: 65572bb34a7e488224b937fc +title: Step 75 +challengeType: 0 +dashedName: step-75 +--- + +# --description-- + +You need to add the `resetText` to the `resetButton` element as a child, and also the `resetButton` to the `playlistSongs` element as a child. For this, there is an `appendChild()` method to use. + +`appendChild()` lets you add a node or an element as the child of another element. In the example below, the text "Click me" would be attached to the button: + +```js +const parentElement = document.createElement("button") +const parentElementText = document.createTextNode("Click me") + +// attach the text "Click me" to the button +parentElement.appendChild(parentElementText) +``` + +Use `appendChild()` to attach `resetText` to `resetButton` element, and `resetButton` to the `playlistSongs` element. + +# --hints-- + +You should use the `appendChild()` method on `resetButton`. + +```js +assert.match(code, /resetButton\.appendChild\(/) +``` + +You should pass in `resetText` as the value of your first `appendChild()`. + +```js +assert.match(code, /resetButton\.appendChild\(resetText\);?/) +``` + +You should use the `appendChild()` method on `playlistSongs`. + +```js +assert.match(code, /playlistSongs\.appendChild\(/) +``` + +You should pass in `resetButton` as the value of your second `appendChild()`. + +```js +assert.match(code, /playlistSongs\.appendChild\(resetButton\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +

                                                                                                                                freeCodeCamp

                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                + song cover art +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +

                                                                                                                                +

                                                                                                                                +
                                                                                                                                +
                                                                                                                                + + + + + +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +

                                                                                                                                Playlist

                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; +--fcc-editable-region-- + +--fcc-editable-region-- + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                • + + +
                                                                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md new file mode 100644 index 00000000000..b8104810cfc --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65572e5aaf022790fb4a81b1.md @@ -0,0 +1,782 @@ +--- +id: 65572e5aaf022790fb4a81b1 +title: Step 76 +challengeType: 0 +dashedName: step-76 +--- + +# --description-- + +Now, it's time to add the reset functionality to the `resetButton`. This will bring back the songs in the playlist when clicked. + +Add a click event listener to the `resetButton` variable. Pass in a callback using arrow syntax and leave it empty for now. + +# --hints-- + +You should use the `addEventListener()` method on `resetButton`. + +```js +assert.match(code, /resetButton\.addEventListener\(/) +``` + +Your `resetButton` event listener should listen for a `click` event. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1/) +``` + +The callback function of your event listener should use arrow syntax and have an empty pair of curly braces. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*\}\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +

                                                                                                                                  freeCodeCamp

                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  + song cover art +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +

                                                                                                                                  +

                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  + + + + + +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +

                                                                                                                                  Playlist

                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                  +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + +--fcc-editable-region-- + +--fcc-editable-region-- + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                  • + + +
                                                                                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md new file mode 100644 index 00000000000..f02c7131cfa --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655737cd004591b0271d6826.md @@ -0,0 +1,779 @@ +--- +id: 655737cd004591b0271d6826 +title: Step 77 +challengeType: 0 +dashedName: step-77 +--- + +# --description-- + +You need to assign the `userData.songs` property to the initial `allSongs` array. This will reset the playlist to its original state. + +Spread `allSongs` into an array and assign it to `userData.songs`. + +# --hints-- + +You should not modify the existing event listener and its content. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*.*\s*\}\);?/) +``` + +You should assign `[...allSongs]` to `userData.songs`. + +```js +assert.match(code, /userData\.songs\s*=\s*\[\.\.\.allSongs\]/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +

                                                                                                                                    freeCodeCamp

                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    + song cover art +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +

                                                                                                                                    +

                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    + + + + + +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +

                                                                                                                                    Playlist

                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                    +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + +--fcc-editable-region-- + resetButton.addEventListener("click", () => { + + }); +--fcc-editable-region-- + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                    • + + +
                                                                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md new file mode 100644 index 00000000000..4540ab905d5 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573a97c59ddbbf028ca95e.md @@ -0,0 +1,798 @@ +--- +id: 65573a97c59ddbbf028ca95e +title: Step 78 +challengeType: 0 +dashedName: step-78 +--- + +# --description-- + +Finally, you should render the songs again, update the play button's accessible text, and remove the reset button from the playlist. You also need to remove the `resetButton` from the DOM. + +Call the `renderSongs()` function with `userData?.songs` as an argument to render the songs again. + +Call the `setPlayButtonAccessibleText()` function to update the play button's accessible text. + +Remove the reset button from the playlist by calling the `remove()` method on the `resetButton` variable. + +**Note**: Now you can try removing all the songs to see what happens. + +# --hints-- + +You should not modify the existing event listener and its content. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*.*\s*.*\s*.*\s*\}\);?/) +``` + +You should call the `renderSongs` function with `userData?.songs`. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*.*\s*.*\s*\}\);?/) +``` + +You should call the `setPlayButtonAccessibleText` function. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*setPlayButtonAccessibleText\(\);?\s*.*\s*\}\);?/) +``` + +You should use the `remove()` method to remove the `resetButton` from the DOM. + +```js +assert.match(code, /resetButton\.addEventListener\(('|")click\1,\s*\(\)\s*=>\s*\{\s*userData\.songs\s*=\s*\[\.\.\.allSongs\];?\s*renderSongs\(userData\?\.songs\);?\s*setPlayButtonAccessibleText\(\);?\s*resetButton\.remove\(\);?\s*\}\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +

                                                                                                                                      freeCodeCamp

                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      + song cover art +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +

                                                                                                                                      +

                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      + + + + + +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +

                                                                                                                                      Playlist

                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                      +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + +--fcc-editable-region-- + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + }); +--fcc-editable-region-- + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                      • + + +
                                                                                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md new file mode 100644 index 00000000000..a0a2edba876 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65573d0abe4d38cd6fa13f44.md @@ -0,0 +1,795 @@ +--- +id: 65573d0abe4d38cd6fa13f44 +title: Step 79 +challengeType: 0 +dashedName: step-79 +--- + +# --description-- + +All the core functionalities are now in place. The only issue now is that the next song does not automatically play when the currently playing song ends. + +To fix that, you can set up an event listener which will detect when the currently playing song ends. The `ended` event listener is appropriate for this. It is fired when the playback of a media reaches the end. + +Add an event listener to the `audio` element which listens for the `ended` event. Pass in a callback using arrow syntax with empty curly braces. + +# --hints-- + +You should chain the `addEventListener()` method to your `audio` variable. + +```js +assert.match(code, /audio\.addEventListener\(/) +``` + +The event listener you used on on your `audio` variable should listen for an `ended` event. + +```js +assert.match(code, /audio\.addEventListener\(('|")ended\1/) +``` + +You should use arrow syntax to pass in an empty callback to your `ended` event listener. + +```js +assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*\}\);?/) +``` + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +

                                                                                                                                        freeCodeCamp

                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        + song cover art +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +

                                                                                                                                        +

                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        + + + + + +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +

                                                                                                                                        Playlist

                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                        +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                        • + + +
                                                                                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +--fcc-editable-region-- + +--fcc-editable-region-- + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md new file mode 100644 index 00000000000..3f0247cec82 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6557421eb6a7a0f0500e3106.md @@ -0,0 +1,756 @@ +--- +id: 6557421eb6a7a0f0500e3106 +title: Step 70 +challengeType: 0 +dashedName: step-70 +--- + +# --description-- + +Within the button element in the `renderSongs` function, add an `onclick` attribute as the first attribute. For the value, call the `deleteSong` function and interpolate `song.id`. + +# --hints-- + +You should add an `onclick` attribute as the first attribute of the delete button and pass in `deleteSong(${song.id})`. + +```js +assert.match(code, //) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +

                                                                                                                                          freeCodeCamp

                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          + song cover art +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +

                                                                                                                                          +

                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          + + + + + +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +

                                                                                                                                          Playlist

                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                          +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                          • + +--fcc-editable-region-- + +--fcc-editable-region-- +
                                                                                                                                          • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md new file mode 100644 index 00000000000..bd6689cf747 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b49333d9f265bc1512152.md @@ -0,0 +1,761 @@ +--- +id: 655b49333d9f265bc1512152 +title: Step 80 +challengeType: 0 +dashedName: step-80 +--- + +# --description-- + +Notice that the album art in the HTML and songs in the `allSongs` array have changed. We've swapped out the original songs for shorter ones that you can use to test your app in the upcoming steps. + +Next, you need to check if there is a next song to play. Retrieve the current song index by calling the `getCurrentSongIndex()` function, and save it in a `currentSongIndex` constant. + +After that, create a `nextSongExists` constant that checks if a next song exists. + +# --hints-- + +You should not modify the existing `ended` event listener and its content. + +```js +assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*.*\s*.*\s*\}\);?/) +``` + +You should create a `currentSongIndex` constant and set it to the calling of the `getCurrentSongIndex` function. + +```js +assert.match(code, /audio\.addEventListener\(('|")ended\1,\s*\(\)\s*=>\s*\{\s*const\s+currentSongIndex\s*=\s*getCurrentSongIndex\(\);?\s*.*\s*\}\);?/) +``` + +You should check if a next song exists with `userData?.songs[currentSongIndex + 1] !== undefined` and set it to a `nextSongExists` constant. + +```js +assert.match(code, /const\s+nextSongExists\s*=\s*userData\?\.songs\[currentSongIndex\s*\+\s*1\]\s*!==\s*undefined;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +

                                                                                                                                            freeCodeCamp

                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            + song cover art +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +

                                                                                                                                            +

                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            + + + + + +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +

                                                                                                                                            Playlist

                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                            +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Hello World", + artist: "RafaelDavisH", + duration: "0:23", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3", + }, + { + id: 1, + title: "In the Zone", + artist: "RafaelDavisH", + duration: "0:11", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3", + }, + { + id: 2, + title: "Camper Cat", + artist: "RafaelDavisH", + duration: "0:21", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3", + }, + { + id: 3, + title: "Electronic", + artist: "RafaelDavisH", + duration: "0:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3", + }, + { + id: 4, + title: "Sailing Away", + artist: "RafaelDavisH", + duration: "0:22", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                            • + + +
                                                                                                                                            • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +--fcc-editable-region-- +audio.addEventListener("ended", () => { + +}); +--fcc-editable-region-- + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md new file mode 100644 index 00000000000..819b3807d15 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4bbff1dbf66cb2ed4dac.md @@ -0,0 +1,753 @@ +--- +id: 655b4bbff1dbf66cb2ed4dac +title: Step 81 +challengeType: 0 +dashedName: step-81 +--- + +# --description-- + +Use an `if` statement to check if `nextSongExists` exists, then call the `playNextSong()` function in the `if` block. This will automatically play the next song when the current song ends. + +# --hints-- + +You should create an `if` statment with the condition `nextSongExists`. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*/) +``` + +You should call the `playNextSong` function inside your `if` statement. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +

                                                                                                                                              freeCodeCamp

                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              + song cover art +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +

                                                                                                                                              +

                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              + + + + + +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +

                                                                                                                                              Playlist

                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                              +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Hello World", + artist: "RafaelDavisH", + duration: "0:23", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3", + }, + { + id: 1, + title: "In the Zone", + artist: "RafaelDavisH", + duration: "0:11", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3", + }, + { + id: 2, + title: "Camper Cat", + artist: "RafaelDavisH", + duration: "0:21", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3", + }, + { + id: 3, + title: "Electronic", + artist: "RafaelDavisH", + duration: "0:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3", + }, + { + id: 4, + title: "Sailing Away", + artist: "RafaelDavisH", + duration: "0:22", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                              • + + +
                                                                                                                                              • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +audio.addEventListener("ended", () => { + const currentSongIndex = getCurrentSongIndex(); + const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined; +--fcc-editable-region-- + +--fcc-editable-region-- +}); + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md new file mode 100644 index 00000000000..3b75e62c99c --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4c8f636d9675953a0388.md @@ -0,0 +1,769 @@ +--- +id: 655b4c8f636d9675953a0388 +title: Step 82 +challengeType: 0 +dashedName: step-82 +--- + +# --description-- + +If there is no next song in the playlist, use the `else` block to reset the `currentSong` key of `userData` to null, and its `songCurrentTime` property to `0`. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*.*\s*.*\s*.*\s*\};?/) +``` + +Your `if` statement should have an `else` block. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*.*\s*.*\s*\};?/) +``` + +You should use dot notation to set the `currentSong` property of `userData` to `null` in the `else` block of your `if` statement. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*userData\.currentSong\s*=\s*null;?\s*.*\s*\};?/) +``` + +You should use dot notation to set the `songCurrentTime` property of `userData` to `0` in the `else` block of your `if`statement. + +```js +assert.match(code, /if\s*\(nextSongExists\)\s*\{\s*playNextSong\(\);?\s*\}\s*else\s*\{\s*userData\.currentSong\s*=\s*null;?\s*userData\.songCurrentTime\s*=\s*0;?\s*\};?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +

                                                                                                                                                freeCodeCamp

                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                + song cover art +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +

                                                                                                                                                +

                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                + + + + + +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +

                                                                                                                                                Playlist

                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Hello World", + artist: "RafaelDavisH", + duration: "0:23", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3", + }, + { + id: 1, + title: "In the Zone", + artist: "RafaelDavisH", + duration: "0:11", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3", + }, + { + id: 2, + title: "Camper Cat", + artist: "RafaelDavisH", + duration: "0:21", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3", + }, + { + id: 3, + title: "Electronic", + artist: "RafaelDavisH", + duration: "0:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3", + }, + { + id: 4, + title: "Sailing Away", + artist: "RafaelDavisH", + duration: "0:22", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                • + + +
                                                                                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +audio.addEventListener("ended", () => { + const currentSongIndex = getCurrentSongIndex(); + const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined; + +--fcc-editable-region-- + if (nextSongExists) { + playNextSong(); + } + +--fcc-editable-region-- +}); + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md new file mode 100644 index 00000000000..a9987ccc07e --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655b4dad1d38ff7cdd65cbfe.md @@ -0,0 +1,1515 @@ +--- +id: 655b4dad1d38ff7cdd65cbfe +title: Step 83 +challengeType: 0 +dashedName: step-83 +--- + +# --description-- + +With everything set in place, call the `pauseSong()`, `setPlayerDisplay()`, `highlightCurrentSong()`, and `setPlayButtonAccessibleText()` functions to correctly update the player. + +Congratulations! Your music player is now complete. You still have the shorter songs for testing, but if you'd like to listen to the original songs, you can copy them from an earlier step and paste them into the `allSongs` array. + +# --hints-- + +You should call the `pauseSong` function. + +```js +const splitter = code.split('audio.addEventListener("ended", () => {') +assert.match(splitter[1], /pauseSong\(\);?/) +``` + +You should call the `setPlayerDisplay` function. + +```js +const splitter = code.split('audio.addEventListener("ended", () => {') +assert.match(splitter[1], /setPlayerDisplay\(\);?/) +``` + +You should call the `highlightCurrentSong` function. + +```js +const splitter = code.split('audio.addEventListener("ended", () => {') +assert.match(splitter[1], /highlightCurrentSong\(\);?/) +``` + +You should call the `setPlayButtonAccessibleText` function. + +```js +const splitter = code.split('audio.addEventListener("ended", () => {') +assert.match(splitter[1], /highlightCurrentSong\(\);?\s*setPlayButtonAccessibleText\(\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +

                                                                                                                                                  freeCodeCamp

                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  + song cover art +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +

                                                                                                                                                  +

                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  + + + + + +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +

                                                                                                                                                  Playlist

                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                  +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Hello World", + artist: "RafaelDavisH", + duration: "0:23", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3", + }, + { + id: 1, + title: "In the Zone", + artist: "RafaelDavisH", + duration: "0:11", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3", + }, + { + id: 2, + title: "Camper Cat", + artist: "RafaelDavisH", + duration: "0:21", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3", + }, + { + id: 3, + title: "Electronic", + artist: "RafaelDavisH", + duration: "0:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3", + }, + { + id: 4, + title: "Sailing Away", + artist: "RafaelDavisH", + duration: "0:22", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                  • + + +
                                                                                                                                                  • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +audio.addEventListener("ended", () => { + const currentSongIndex = getCurrentSongIndex(); + const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined; + + if (nextSongExists) { + playNextSong(); + } else { + userData.currentSong = null; + userData.songCurrentTime = 0; +--fcc-editable-region-- + + +--fcc-editable-region-- + } +}); + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` + +# --solutions-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +

                                                                                                                                                    freeCodeCamp

                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    + song cover art +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +

                                                                                                                                                    +

                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    + + + + + +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +

                                                                                                                                                    Playlist

                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                    +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Hello World", + artist: "RafaelDavisH", + duration: "0:23", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/hello-world.mp3", + }, + { + id: 1, + title: "In the Zone", + artist: "RafaelDavisH", + duration: "0:11", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/in-the-zone.mp3", + }, + { + id: 2, + title: "Camper Cat", + artist: "RafaelDavisH", + duration: "0:21", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/camper-cat.mp3", + }, + { + id: 3, + title: "Electronic", + artist: "RafaelDavisH", + duration: "0:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/electronic.mp3", + }, + { + id: 4, + title: "Sailing Away", + artist: "RafaelDavisH", + duration: "0:22", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/sailing-away.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () =>{ + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + const resetText = document.createTextNode("Reset Playlist"); + + resetButton.id = "reset"; + resetButton.ariaLabel = "Reset playlist"; + resetButton.appendChild(resetText); + playlistSongs.appendChild(resetButton); + + resetButton.addEventListener("click", () => { + userData.songs = [...allSongs]; + + renderSongs(userData?.songs); + setPlayButtonAccessibleText(); + resetButton.remove(); + }); + + } + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                    • + + +
                                                                                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +audio.addEventListener("ended", () => { + const currentSongIndex = getCurrentSongIndex(); + const nextSongExists = userData?.songs[currentSongIndex + 1] !== undefined; + + if (nextSongExists) { + playNextSong(); + } else { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + } +}); + +renderSongs(userData?.songs); +setPlayButtonAccessibleText(); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md new file mode 100644 index 00000000000..68b1fbbab97 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/655dc43318591b975cdfe2d8.md @@ -0,0 +1,576 @@ +--- +id: 655dc43318591b975cdfe2d8 +title: Step 4 +challengeType: 0 +dashedName: step-4 +--- + +# --description-- + +Inside the `allSongs` array, create an object with the following properties and values: + +```js +id: 0, +title: "Scratching The Surface", +artist: "Quincy Larson", +duration: "4:25", +src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", +``` + +# --hints-- + +Your `allSongs` array should have one value. + +```js +assert.equal(allSongs.length, 1); +``` + +Your `allSongs` array should have an object as its first value. + +```js +assert.isObject(allSongs[0]); +``` + +Your `allSongs` array should have an object with an `id` property set to the number `0`. + +```js +assert.equal(allSongs[0].id, 0); +``` + +Your `allSongs` array should have an object with a `title` property set to the string `Scratching The Surface`. + +```js +assert.equal(allSongs[0].title, "Scratching The Surface"); +``` + +Your `allSongs` array should have an object with an `artist` property set to the string `Quincy Larson`. + +```js +assert.equal(allSongs[0].artist, "Quincy Larson"); +``` + +Your `allSongs` array should have an object with a `duration` property set to the string `4:25`. + +```js +assert.equal(allSongs[0].duration, "4:25"); +``` + +Your `allSongs` array should have an object with an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3`. + +```js +assert.equal(allSongs[0].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3"); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +

                                                                                                                                                      freeCodeCamp

                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      + song cover art +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +

                                                                                                                                                      +

                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      + + + + + +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +

                                                                                                                                                      Playlist

                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                      +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ +--fcc-editable-region-- + +--fcc-editable-region-- +]; +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md new file mode 100644 index 00000000000..01af8592a30 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606d06666e118ba86162be.md @@ -0,0 +1,584 @@ +--- +id: 65606d06666e118ba86162be +title: Step 5 +challengeType: 0 +dashedName: step-5 +--- + +# --description-- + +Add a second object with the following keys and values: + +```js +id: 1, +title: "Can't Stay Down", +artist: "Quincy Larson", +duration: "4:15", +src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", +``` + +# --hints-- + +Your `allSongs` array should have two values. + +```js +assert.equal(allSongs.length, 2); +``` + +Your `allSongs` array should have an object as its second value. + +```js +assert.isObject(allSongs[1]); +``` + +The second object in your `allSongs` array should have an `id` property set to the number `1`. + +```js +assert.equal(allSongs[1].id, 1); +``` + +The second object in your `allSongs` array should have a `title` property set to the string `Can't Stay Down`. + +```js +assert.equal(allSongs[1].title, "Can't Stay Down"); +``` + +The second object in your `allSongs` array should have an `artist` property set to the string `Quincy Larson`. + +```js +assert.equal(allSongs[1].artist, "Quincy Larson"); +``` + +The second object in your `allSongs` array should have a `duration` property set to the string `4:15`. + +```js +assert.equal(allSongs[1].duration, "4:15"); +``` + +The second object in your `allSongs` array should have an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3`. + +```js +assert.equal(allSongs[1].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3"); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +

                                                                                                                                                        freeCodeCamp

                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        + song cover art +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +

                                                                                                                                                        +

                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        + + + + + +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +

                                                                                                                                                        Playlist

                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                        +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + +--fcc-editable-region-- + +--fcc-editable-region-- +]; +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md new file mode 100644 index 00000000000..305a1d7b573 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65606ed6ea2baca053327e9b.md @@ -0,0 +1,586 @@ +--- +id: 65606ed6ea2baca053327e9b +title: Step 6 +challengeType: 0 +dashedName: step-6 +--- + +# --description-- + +Add a third object with the following properties and values: + +```js + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", +``` + +# --hints-- + +Your `allSongs` array should have an object as its third value. + +```js +assert.isObject(allSongs[2]); +``` + +The third object in your `allSongs` array should have an `id` property set to the number `2`. + +```js +assert.equal(allSongs[2].id, 2); +``` + +The third object in your `allSongs` array should have a `title` property set to the string `Still Learning`. + +```js +assert.equal(allSongs[2].title, "Still Learning"); +``` + +The third object in your `allSongs` array should have an `artist` property set to the string `Quincy Larson`. + +```js +assert.equal(allSongs[2].artist, "Quincy Larson"); +``` + +The third object in your `allSongs` array should have a `duration` property set to the string `4:15`. + +```js +assert.equal(allSongs[2].duration, "3:51"); +``` + +The third object in your `allSongs` array should have an `src` property set to the string `https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3`. + +```js +assert.equal(allSongs[2].src, "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3"); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +

                                                                                                                                                          freeCodeCamp

                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          + song cover art +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +

                                                                                                                                                          +

                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          + + + + + +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +

                                                                                                                                                          Playlist

                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                          +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + +--fcc-editable-region-- + +--fcc-editable-region-- +]; +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md new file mode 100644 index 00000000000..fa17aed79ae --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656071d679089ebd9d5035a0.md @@ -0,0 +1,618 @@ +--- +id: 656071d679089ebd9d5035a0 +title: Step 9 +challengeType: 0 +dashedName: step-9 +--- + +# --description-- + +Now you should update the `userData` object to include a `songs` property. For this you will be using the `spread` operator. + +The spread operator `...` allows you to create a new array by copying all the elements from an existing array into another array. In the example below, both, `arr1` and `arr2` have been spread into `combinedArr`: + +```js +const arr1 = [1, 2, 3]; +const arr2 = [4, 5, 6]; + +const combinedArr = [...arr1, ...arr2]; +console.log(combinedArr); // Output: [1, 2, 3, 4, 5, 6] +``` + +Inside the `userData` object create a `songs` property. For the value spread `allSongs` into an array. + +# --hints-- + +Your `userData` object should have a `songs` key set to `[...allSongs]`. + +```js +assert.match(code, /songs:\s*\[\.\.\.allSongs\],?/); +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +

                                                                                                                                                            freeCodeCamp

                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            + song cover art +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +

                                                                                                                                                            +

                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            + + + + + +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +

                                                                                                                                                            Playlist

                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                            +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +--fcc-editable-region-- +let userData = { + +}; +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md new file mode 100644 index 00000000000..dbc320e4302 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656073a2b98232c8aca72267.md @@ -0,0 +1,620 @@ +--- +id: 656073a2b98232c8aca72267 +title: Step 10 +challengeType: 0 +dashedName: step-10 +--- + +# --description-- + +To handle the current song's information and track the song's playback time, create a `currentSong` and `songCurrentTime` properties. Set the values to `null` and `0` respectively. + +# --hints-- + +You should not modify the existing `userData` object and its content. + +```js +assert.match(code, /let\s*userData\s*=\s*\{\s*songs:\s*\[\.\.\.allSongs\],?\s*/); +``` + +Your `userData` object should have a `currentSong` key set to `null`. + +```js +assert.propertyVal(userData, "currentSong", null) +``` + +Your `userData` object should have a `songCurrentTime` key set to `0`. + +```js +assert.propertyVal(userData, "songCurrentTime", 0) +``` + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              freeCodeCamp

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + song cover art +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              +

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              + + + + + +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +

                                                                                                                                                              Playlist

                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                              +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +--fcc-editable-region-- +let userData = { + songs: [...allSongs], + +}; +--fcc-editable-region-- +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md new file mode 100644 index 00000000000..618b4e2bc15 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/656472ed8f552d2f2b3f7883.md @@ -0,0 +1,659 @@ +--- +id: 656472ed8f552d2f2b3f7883 +title: Step 24 +challengeType: 0 +dashedName: step-24 +--- + +# --description-- + +Add an `else` block to handle the current song's position in the playlist. + +Within the `else` block, set the `currentTime` property of the `audio` object to the value stored in `userData.songCurrentTime`. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}/) +``` + +You should add an `else` block to the existing `if` block. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}\s*else\s{/) +``` + +You should set `audio.currentTime` to `userData.songCurrentTime` inside the `else` block of your `if` statement. + +```js +assert.match(code, /if\s*\(userData\?\.currentSong\s*===\s*null\s*\|\|\s*userData\?\.currentSong\.id\s*!==\s*song\.id\)\s*\{\s*audio\.currentTime\s*=\s*0;?\s*\}\s*else\s{\s*audio\.currentTime\s*=\s*userData\.songCurrentTime;?\s*\}/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +

                                                                                                                                                                freeCodeCamp

                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                + song cover art +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +

                                                                                                                                                                +

                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                + + + + + +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +

                                                                                                                                                                Playlist

                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + +--fcc-editable-region-- + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } + + +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                                • + + +
                                                                                                                                                                • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md new file mode 100644 index 00000000000..04bdebd08ca --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/6567055f59d39f07d1c542dc.md @@ -0,0 +1,634 @@ +--- +id: 6567055f59d39f07d1c542dc +title: Step 18 +challengeType: 0 +dashedName: step-18 +--- + +# --description-- + +Next, you will need to update the playlist in your HTML document to display the songs. + +Add `songsHTML` to `playlistSongs`, by using the `innerHTML` property. This will insert the `li` element you just created into the `ul` element in the already provided `HTML` file. + +# --hints-- + +You should use the `innerHTML` property to add `songsHTML` to `playlistSongs`. + +```js +assert.match(code, /playlistSongs\.innerHTML\s*=\s*songsHTML;?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +

                                                                                                                                                                  freeCodeCamp

                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  + song cover art +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +

                                                                                                                                                                  +

                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  + + + + + +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +

                                                                                                                                                                  Playlist

                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                  +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); + +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                                  • + + +
                                                                                                                                                                  • + `; + }) + .join(""); + +--fcc-editable-region-- + +--fcc-editable-region-- +}; + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md new file mode 100644 index 00000000000..9eec8b6486f --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65671421254eeb489875cdd8.md @@ -0,0 +1,711 @@ +--- +id: 65671421254eeb489875cdd8 +title: Step 48 +challengeType: 0 +dashedName: step-48 +--- + +# --description-- + +Within the callback function, use the `removeAttribute()` method to remove the `"aria-current"` attribute. This will remove the attribute for each of the songs. + +# --hints-- + +You should not modify the existing `forEach()` and its content. + +```js +assert.match(code, /playlistSongElements\.forEach\(\(songEl\)\s*=>\s*\{\s*/) +``` + +You should use the `removeAttribute()` method on `songEl` and pass in `"aria-current"`. + +```js +assert.match(code, /playlistSongElements\.forEach\(\(songEl\)\s*=>\s*\{\s*songEl\.removeAttribute\(('|")aria-current\1\);?\s*\}\);?/) +``` + + + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +

                                                                                                                                                                    freeCodeCamp

                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    + song cover art +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +

                                                                                                                                                                    +

                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    + + + + + +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +

                                                                                                                                                                    Playlist

                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                    +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + +--fcc-editable-region-- + playlistSongElements.forEach((songEl) => { + + }); +--fcc-editable-region-- +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                                    • + + +
                                                                                                                                                                    • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +renderSongs(userData?.songs); +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md new file mode 100644 index 00000000000..eeeba9e0374 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672136535209761a5cf02b.md @@ -0,0 +1,660 @@ +--- +id: 65672136535209761a5cf02b +title: Step 30 +challengeType: 0 +dashedName: step-30 +--- + +# --description-- + +To play the song anytime the user clicks on it, add an `onclick` attribute to the first button element. Inside the `onclick`, call the `playSong` function with `song.id`. + +Don't forget you need to interpolate with the dollar sign here. + +# --hints-- + +You should add an `onclick` with the value `playSong(${song.id})` as the second attribute and value of the `button` element. + +```js +assert.match(code, /\s*\$\{song\.title\}<\/span>\s*\$\{song\.artist\}<\/span>\s*\$\{song\.duration\}<\/span>\s*<\/button>/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +

                                                                                                                                                                      freeCodeCamp

                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      + song cover art +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +

                                                                                                                                                                      +

                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      + + + + + +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +

                                                                                                                                                                      Playlist

                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                      +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + audio.play(); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                                      • +--fcc-editable-region-- + +--fcc-editable-region-- + +
                                                                                                                                                                      • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + }else { + playSong(userData?.currentSong.id); + } +}); + + +renderSongs(userData?.songs); + +``` diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md new file mode 100644 index 00000000000..2c938e89234 --- /dev/null +++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-string-and-array-methods-by-building-a-music-player/65672adafbaa37a6cef886f7.md @@ -0,0 +1,788 @@ +--- +id: 65672adafbaa37a6cef886f7 +title: Step 73 +challengeType: 0 +dashedName: step-73 +--- + +# --description-- + +Now that you've created the button, you need to assign it a text. To do this, you need to use the `createTextNode()` method of DOM. + +The `createTextNode()` method is used to create a text node. To use it, you call it and pass in the text as a string: + +```js +document.createTextNode("your text") +``` + +You can also assign it to a variable: + +```js +const myText = document.createTextNode("your text") +``` + +Use the `createTextNode()` method to create a `Reset Playlist` text, then assign it to a `resetText` constant. + +# --hints-- + +You should not modify the existing `if` statement and its content. + +```js +assert.match(code, /if\s*\(userData\.songs\.length\s*===\s*0\)\s*\{\s*const\s+resetButton\s*=\s*document\.createElement\(('|")button\1\);?\s*.*\s*\}/) +``` + +You should use `document.createTextNode()` to create a `Reset Playlist` text. + +```js +assert.match(code, /document\.createTextNode\(('|")Reset\s+Playlist\1\);?/) +``` + +You should assign your created text node to a `resetText` constant. + +```js +assert.match(code, /const\s+resetText\s*=\s*document\.createTextNode\(('|")Reset\s+Playlist\1\);?/) +``` + +# --seed-- + +## --seed-contents-- + +```html + + + + + + + + + + Learn Basic String and Array Methods by Building a Music Player App + + + + +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +

                                                                                                                                                                        freeCodeCamp

                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        + song cover art +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +

                                                                                                                                                                        +

                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        + + + + + +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +

                                                                                                                                                                        Playlist

                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                        +
                                                                                                                                                                          +
                                                                                                                                                                          +
                                                                                                                                                                          + + + +``` + +```css +:root { + /* colors */ + --primary-color: #dfdfe2; + --secondary-color: #ffffff; + --app-background-color: #4d4d62; + --background-color: #1b1b32; + --foreground-color: #3b3b4f; + --highlight-color: #f1be32; + + /* font sizes */ + --root-font-size: 16px; + font-size: var(--root-font-size); + + /* font-families */ + --font-headline: "Roboto Mono", monospace; + --font-family: "Lato", sans-serif; +} + +*, +*::after, +*::before { + box-sizing: border-box; +} + +body { + background-color: var(--app-background-color); + color: var(--primary-color); + font-family: var(--font-family); +} + +h1 { + font-size: 1.125rem; + line-height: 1.6; +} + +h2 { + font-size: var(--root-font-size); +} + +ul { + margin: 0; +} + +.container { + margin-top: 10px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + row-gap: 5px; +} + +.player, +.playlist { + width: 450px; + background-color: var(--background-color); + border: 3px solid var(--foreground-color); +} + +.player { + height: 260px; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +.player-bar, +.playlist-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 5px; + width: 100%; + height: 30px; + background-color: var(--foreground-color); +} + +.parallel-lines { + display: flex; + flex-wrap: wrap; + row-gap: 6px; + padding: 0 5px; +} + +.parallel-lines > div { + height: 2px; + width: 100%; + min-width: 75px; + background-color: var(--highlight-color); +} + +.fcc-title, +.playlist-title { + color: var(--secondary-color); + margin: 0 10px; + font-family: var(--font-headline); +} + +.player-content { + display: flex; + background-color: var(--foreground-color); + width: 430px; + height: 200px; + column-gap: 13px; + align-items: center; + justify-content: center; +} + +#player-album-art { + background-color: var(--secondary-color); + border: 6px solid var(--background-color); +} + +#player-album-art img { + width: 150px; + display: block; +} + +.player-display { + display: flex; + flex-direction: column; + row-gap: 20px; + padding: 14px; + background-color: var(--background-color); + height: 153px; + width: 226px; +} + +.player-display-song-artist { + height: 80px; +} + +.player-buttons svg { + fill: var(--primary-color); +} + +.playing > svg { + fill: var(--highlight-color); +} + +.player-buttons { + display: flex; + justify-content: space-around; +} + +button { + background: transparent; + border: none; + color: var(--primary-color); + cursor: pointer; + font-size: var(--root-font-size); + outline-color: var(--highlight-color); + text-align: center; +} + +.playlist-song { + outline-color: var(--highlight-color); +} + +.playlist li:not(:last-child) { + border-bottom: 1px solid var(--background-color); +} + +button:focus, +.playlist-song:focus { + outline-style: dashed; + outline-width: 2px; +} + +/* Playlist */ +.playlist { + height: auto; + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + row-gap: 10px; +} + +#playlist-songs { + width: 430px; + height: 100%; + background-color: var(--foreground-color); + display: flex; + flex-direction: column; + row-gap: 8px; + padding: 8px 9px; + visibility: visible; + justify-content: start; + list-style: none; +} + +.playlist-song { + display: flex; + height: 55px; + justify-content: space-between; + align-items: center; + padding: 5px; +} + +[aria-current="true"] { + background-color: var(--background-color); +} + +[aria-current="true"] p { + color: var(--highlight-color); +} + +.playlist-song-info { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + column-gap: 7px; + padding: 5px 0; + font-family: var(--font-family); +} + +#player-song-title, +#player-song-artist { + margin: 0; +} + +#player-song-artist { + color: var(--highlight-color); + font-size: 0.75rem; +} + +#player-song-title { + font-size: 1.125rem; +} + +.playlist-song-title { + font-size: 0.85rem; + width: 241px; + text-align: left; +} + +.playlist-song-artist { + font-size: 0.725rem; + width: 80px; +} + +.playlist-song-duration { + font-size: 0.725rem; + margin: auto; + font-family: var(--font-headline); + width: 30px; +} + +.playlist-song-delete { + padding: 0; + width: 20px; + height: 20px; +} + +.playlist-song-delete, +.playlist-song-delete { + fill: var(--foreground-color); +} + +.playlist-song-delete:hover circle, +.playlist-song-delete:focus circle { + fill: #ff0000; +} + +@media (max-width: 700px) { + .player, + .playlist { + width: 300px; + } + + .player { + height: 340px; + } + + #playlist-songs { + height: 280px; + padding: 5px 6px; + overflow-y: scroll; + overflow-x: hidden; + scrollbar-color: var(--background-color) var(--secondary-color); + scrollbar-width: thin; + } + + #playlist-songs::-webkit-scrollbar { + width: 5px; + } + + #playlist-songs::-webkit-scrollbar-track { + background: var(--background-color); + } + + #playlist-songs::-webkit-scrollbar-thumb { + background: var(--secondary-color); + } + + h1 { + font-size: 0.813rem; + } + + h2 { + font-size: 0.75rem; + } + + .player-bar, + .playlist-bar, + .player-content, + #playlist-songs { + width: 280px; + } + + .playlist-song { + justify-content: space-between; + } + + .playlist-song-title { + width: 140px; + } + + .playlist-song-artist { + width: 40px; + } + + .playlist-song-duration > button { + padding: 0; + } + + .player-content { + display: inline; + position: relative; + justify-items: center; + height: 100%; + } + + #player-album-art { + z-index: -100; + height: 280px; + box-shadow: none; + background: #000; + } + + #player-album-art img { + width: 100%; + opacity: 0.6; + } + + .player-display-song-artist { + padding: 0 10px; + } + + .player-display-song-artist > p { + white-space: pre-wrap; + } + + .player-display { + position: absolute; + width: 100%; + z-index: 1000; + background-color: transparent; + top: 0; + height: 280px; + justify-content: space-between; + text-align: center; + } +} +``` + +```js +const playlistSongs = document.getElementById("playlist-songs"); +const playButton = document.getElementById("play"); +const pauseButton = document.getElementById("pause"); +const nextButton = document.getElementById("next"); +const previousButton = document.getElementById("previous"); +const shuffleButton = document.getElementById("shuffle"); + +const allSongs = [ + { + id: 0, + title: "Scratching The Surface", + artist: "Quincy Larson", + duration: "4:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/scratching-the-surface.mp3", + }, + { + id: 1, + title: "Can't Stay Down", + artist: "Quincy Larson", + duration: "4:15", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stay-down.mp3", + }, + { + id: 2, + title: "Still Learning", + artist: "Quincy Larson", + duration: "3:51", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/still-learning.mp3", + }, + { + id: 3, + title: "Cruising for a Musing", + artist: "Quincy Larson", + duration: "3:34", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cruising-for-a-musing.mp3", + }, + { + id: 4, + title: "Never Not Favored", + artist: "Quincy Larson", + duration: "3:35", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/never-not-favored.mp3", + }, + { + id: 5, + title: "From the Ground Up", + artist: "Quincy Larson", + duration: "3:12", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/from-the-ground-up.mp3", + }, + { + id: 6, + title: "Walking on Air", + artist: "Quincy Larson", + duration: "3:25", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/walking-on-air.mp3", + }, + { + id: 7, + title: "Can't Stop Me. Can't Even Slow Me Down.", + artist: "Quincy Larson", + duration: "3:52", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/cant-stop-me-cant-even-slow-me-down.mp3", + }, + { + id: 8, + title: "The Surest Way Out is Through", + artist: "Quincy Larson", + duration: "3:10", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/the-surest-way-out-is-through.mp3", + }, + { + id: 9, + title: "Chasing That Feeling", + artist: "Quincy Larson", + duration: "2:43", + src: "https://s3.amazonaws.com/org.freecodecamp.mp3-player-project/chasing-that-feeling.mp3", + }, +]; + +const audio = new Audio(); +let userData = { + songs: [...allSongs], + currentSong: null, + songCurrentTime: 0, +}; + +const playSong = (id) => { + const song = userData?.songs.find((song) => song.id === id); + audio.src = song.src; + audio.title = song.title; + + if (userData?.currentSong === null || userData?.currentSong.id !== song.id) { + audio.currentTime = 0; + } else { + audio.currentTime = userData.songCurrentTime; + } + userData.currentSong = song; + playButton.classList.add("playing"); + + highlightCurrentSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); + audio.play(); +}; + +const pauseSong = () => { + userData.songCurrentTime = audio.currentTime; + + playButton.classList.remove("playing"); + audio.pause(); +}; + +const playNextSong = () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + const currentSongIndex = getCurrentSongIndex(); + const nextSong = userData?.songs[currentSongIndex + 1]; + + playSong(nextSong.id); + } +}; + +const playPreviousSong = () => { + if (userData?.currentSong === null) return; + else { + const currentSongIndex = getCurrentSongIndex(); + const previousSong = userData?.songs[currentSongIndex - 1]; + + playSong(previousSong.id); + } +}; + +const shuffle = () => { + userData?.songs.sort(() => Math.random() - 0.5); + userData.currentSong = null; + userData.songCurrentTime = 0; + + renderSongs(userData?.songs); + pauseSong(); + setPlayerDisplay(); + setPlayButtonAccessibleText(); +}; + +const deleteSong = (id) => { + if (userData?.currentSong?.id === id) { + userData.currentSong = null; + userData.songCurrentTime = 0; + + pauseSong(); + setPlayerDisplay(); + } + + userData.songs = userData?.songs.filter((song) => song.id !== id); + renderSongs(userData?.songs); + highlightCurrentSong(); + setPlayButtonAccessibleText(); + +--fcc-editable-region-- + if (userData.songs.length === 0) { + const resetButton = document.createElement("button"); + + + } +--fcc-editable-region-- + +}; + +const setPlayerDisplay = () => { + const playingSong = document.getElementById("player-song-title"); + const songArtist = document.getElementById("player-song-artist"); + const currentTitle = userData?.currentSong?.title; + const currentArtist = userData?.currentSong?.artist; + + playingSong.textContent = currentTitle ? currentTitle : ""; + songArtist.textContent = currentArtist ? currentArtist : ""; +}; + +const highlightCurrentSong = () => { + const playlistSongElements = document.querySelectorAll(".playlist-song"); + const songToHighlight = document.getElementById( + `song-${userData?.currentSong?.id}` + ); + + playlistSongElements.forEach((songEl) => { + songEl.removeAttribute("aria-current"); + }); + + if (songToHighlight) songToHighlight.setAttribute("aria-current", "true"); +}; + +const renderSongs = (array) => { + const songsHTML = array + .map((song)=> { + return ` +
                                                                                                                                                                        • + + +
                                                                                                                                                                        • + `; + }) + .join(""); + + playlistSongs.innerHTML = songsHTML; +}; + +const setPlayButtonAccessibleText = () => { + const song = userData?.currentSong || userData?.songs[0]; + + playButton.setAttribute( + "aria-label", + song?.title ? `Play ${song.title}` : "Play" + ); +}; + +const getCurrentSongIndex = () => userData?.songs.indexOf(userData.currentSong); + +playButton.addEventListener("click", () => { + if (userData?.currentSong === null) { + playSong(userData?.songs[0].id); + } else { + playSong(userData?.currentSong.id); + } +}); + +pauseButton.addEventListener("click", pauseSong); + +nextButton.addEventListener("click", playNextSong); + +previousButton.addEventListener("click", playPreviousSong); + +shuffleButton.addEventListener("click", shuffle); + +renderSongs(userData?.songs); +```