├── tasks.txt ├── icon.png ├── Cover.png ├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── logo512.png ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── manifest.json └── index.html ├── src ├── Layouts │ ├── sm.png │ ├── Library.js │ └── About.js ├── Styles │ ├── elements │ │ ├── _menu-icon.scss │ │ ├── _menu-title.scss │ │ ├── _library-close-icon.scss │ │ ├── _about-headline.scss │ │ ├── _about-img.scss │ │ ├── _library-song-artist.scss │ │ ├── _about-question.scss │ │ ├── _about-button.scss │ │ ├── _player-duration.scss │ │ ├── _library-song-cover.scss │ │ ├── _song-info-title.scss │ │ ├── _song-info-artist.scss │ │ ├── _artwork.scss │ │ ├── _player-control-icon.scss │ │ └── _player-seek-bar.scss │ ├── components │ │ ├── _song-info.scss │ │ ├── _nav-header.scss │ │ ├── _player.scss │ │ ├── _player-seek-controls.scss │ │ ├── _player-control.scss │ │ ├── _about-socials.scss │ │ └── _library-list-item.scss │ ├── common │ │ ├── _animations.scss │ │ └── _variables.scss │ ├── base │ │ └── _base.scss │ ├── layouts │ │ ├── _about.scss │ │ ├── _library.scss │ │ └── _home.scss │ └── app.scss ├── Utils │ ├── Shadows.js │ ├── Colors.js │ └── Gradients.js ├── Elements │ ├── About │ │ ├── AboutHeaderTitle.js │ │ ├── AboutHeadline.js │ │ ├── AboutQuestionTitle.js │ │ ├── AboutImg.js │ │ ├── AboutQuestionAnswer.js │ │ ├── AboutHeaderCloseIcon.js │ │ └── AboutButton.js │ ├── Common │ │ ├── MenuTitle.js │ │ └── MenuIcon.js │ ├── Library │ │ ├── LibraryHeaderTitle.js │ │ ├── LibrarySongTitle.js │ │ ├── LibrarySongArtist.js │ │ ├── LibraryHeaderCloseIcon.js │ │ └── LibrarySongCover.js │ └── Main │ │ ├── PlayerDuration.js │ │ ├── SongInfoTitle.js │ │ ├── SongInfoArtist.js │ │ ├── Artwork.js │ │ ├── PlayerSeekBar.js │ │ └── PlayerPlayButton.js ├── reportWebVitals.js ├── Components │ ├── Common │ │ └── MenuHeader.js │ ├── Main │ │ ├── SongInfo.js │ │ ├── SeekControl.js │ │ └── PlayerControl.js │ ├── About │ │ └── AboutHeader.js │ ├── Library │ │ ├── LibraryHeader.js │ │ └── LibraryListItem.js │ └── PlayerInterface │ │ └── Player.js ├── index.js ├── service-worker.js ├── App.js ├── serviceWorkerRegistration.js └── Data │ └── SongData.js ├── tempCodeRunnerFile.js ├── .gitignore ├── test.js ├── LICENSE ├── package.json └── README.md /tasks.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/icon.png -------------------------------------------------------------------------------- /Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/Cover.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/Layouts/sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/src/Layouts/sm.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/priyanshu-bharti/chillypopper-react/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /src/Styles/elements/_menu-icon.scss: -------------------------------------------------------------------------------- 1 | .menu { 2 | &__icon { 3 | font-size: $font-size-menu-icon; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/Styles/elements/_menu-title.scss: -------------------------------------------------------------------------------- 1 | .menu { 2 | &__title { 3 | font-size: $font-size-menu-title; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tempCodeRunnerFile.js: -------------------------------------------------------------------------------- 1 | 2 | // console.log(((totalSongs + currentSongIndex) % totalSongs) + 1); 3 | // currentSongIndex++; 4 | // } -------------------------------------------------------------------------------- /src/Styles/components/_song-info.scss: -------------------------------------------------------------------------------- 1 | .song-info { 2 | display: flex; 3 | flex-direction: column; 4 | gap: $clamp-song-info-gap; 5 | } 6 | -------------------------------------------------------------------------------- /src/Styles/elements/_library-close-icon.scss: -------------------------------------------------------------------------------- 1 | .library__menu { 2 | &__icon { 3 | font-size: $font-size-menu-icon * 1.3; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/Styles/elements/_about-headline.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | &__headline { 3 | font-size: 3rem; 4 | // padding-top: 2rem; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Styles/elements/_about-img.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | &__img { 3 | width: clamp(28rem, 80vw, 40rem); 4 | margin: 0 auto; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Styles/components/_nav-header.scss: -------------------------------------------------------------------------------- 1 | .nav__header { 2 | padding: $space-sm; 3 | display: flex; 4 | align-items: center; 5 | justify-content: space-between; 6 | } 7 | -------------------------------------------------------------------------------- /src/Utils/Shadows.js: -------------------------------------------------------------------------------- 1 | const shadow = (x = 0, y = 0, b = 0, s = 0, color = "#000000") => { 2 | return `${x}px ${y}px ${b}px ${s}px ${color}5c`; 3 | }; 4 | 5 | export default shadow; 6 | -------------------------------------------------------------------------------- /src/Elements/About/AboutHeaderTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function MenuTitle() { 4 | return

About

; 5 | } 6 | 7 | export default MenuTitle; 8 | -------------------------------------------------------------------------------- /src/Elements/Common/MenuTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function MenuTitle() { 4 | return

ChillyPopper

; 5 | } 6 | 7 | export default MenuTitle; 8 | -------------------------------------------------------------------------------- /src/Elements/Library/LibraryHeaderTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function MenuTitle() { 4 | return

Library

; 5 | } 6 | 7 | export default MenuTitle; 8 | -------------------------------------------------------------------------------- /src/Styles/elements/_library-song-artist.scss: -------------------------------------------------------------------------------- 1 | .library { 2 | &__song { 3 | &--artist { 4 | font-weight: 300; 5 | font-size: 1.4rem; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Styles/common/_animations.scss: -------------------------------------------------------------------------------- 1 | @keyframes spinning { 2 | 0% { 3 | -webkit-transform: rotate(0deg); 4 | } 5 | 100% { 6 | -webkit-transform: rotate(359deg); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Elements/Main/PlayerDuration.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function PlayerDuration({ value }) { 4 | return

{value}

; 5 | } 6 | 7 | export default PlayerDuration; 8 | -------------------------------------------------------------------------------- /src/Elements/About/AboutHeadline.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function AboutHeadline({ content }) { 4 | return

{content}

; 5 | } 6 | 7 | export default AboutHeadline; 8 | -------------------------------------------------------------------------------- /src/Styles/components/_player.scss: -------------------------------------------------------------------------------- 1 | .player { 2 | display: flex; 3 | flex-direction: column; 4 | height: 100%; 5 | justify-content: space-evenly; 6 | padding: $space-sm 0; 7 | gap: $space-sm; 8 | } 9 | -------------------------------------------------------------------------------- /src/Elements/About/AboutQuestionTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function AboutQuestionTitle({ content }) { 4 | return

{content}

; 5 | } 6 | 7 | export default AboutQuestionTitle; 8 | -------------------------------------------------------------------------------- /src/Elements/Library/LibrarySongTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function LibrarySongTitle({ song }) { 4 | return

{song.title}

; 5 | } 6 | 7 | export default LibrarySongTitle; 8 | -------------------------------------------------------------------------------- /src/Elements/Library/LibrarySongArtist.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function LibrarySongArtist({ song }) { 4 | return

{song.artist}

; 5 | } 6 | 7 | export default LibrarySongArtist; 8 | -------------------------------------------------------------------------------- /src/Elements/About/AboutImg.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import img from "../../Layouts/sm.png"; 3 | 4 | function AboutImg() { 5 | return Artwork; 6 | } 7 | 8 | export default AboutImg; 9 | -------------------------------------------------------------------------------- /src/Elements/About/AboutQuestionAnswer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function AboutQuestionAnswer({ content }) { 4 | return

{content}

; 5 | } 6 | 7 | export default AboutQuestionAnswer; 8 | -------------------------------------------------------------------------------- /src/Elements/Main/SongInfoTitle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function SongInfoTitle({ songState }) { 4 | return ( 5 |

{songState.currentSong[0].title}

6 | ); 7 | } 8 | 9 | export default SongInfoTitle; 10 | -------------------------------------------------------------------------------- /src/Styles/elements/_about-question.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | &__question { 3 | font-size: 2rem; 4 | padding-bottom: 1rem; 5 | 6 | &--answer { 7 | font-size: 1.35rem; 8 | line-height: 2.5rem; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Styles/components/_player-seek-controls.scss: -------------------------------------------------------------------------------- 1 | .player { 2 | &__seek-controls { 3 | display: flex; 4 | gap: $space-xsm; 5 | width: $clamp-player-seek-control-width; 6 | align-items: center; 7 | justify-content: space-between; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Styles/elements/_about-button.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | text-decoration: none; 3 | color: $color-white; 4 | font-weight: 600; 5 | padding: 2rem 3rem; 6 | width: max-content; 7 | align-self: center; 8 | border-radius: 1.5rem; 9 | margin-bottom: 2rem; 10 | } 11 | -------------------------------------------------------------------------------- /src/Styles/components/_player-control.scss: -------------------------------------------------------------------------------- 1 | .player__control { 2 | display: flex; 3 | gap: 2.5rem; 4 | align-items: center; 5 | max-width: 50rem; 6 | align-self: center; 7 | } 8 | 9 | @media only screen and (min-width: 900px) { 10 | .player__control { 11 | gap: 5rem; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Styles/elements/_player-duration.scss: -------------------------------------------------------------------------------- 1 | .player { 2 | &__duration { 3 | font-size: $font-size-time-duration; 4 | font-weight: $font-weight-player-duration; 5 | color: $color-darkgrey; 6 | width: 4rem; 7 | text-align: center; 8 | margin-top: 0.1rem; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Styles/elements/_library-song-cover.scss: -------------------------------------------------------------------------------- 1 | .library { 2 | &__song--cover { 3 | height: 8rem; 4 | width: 8rem; 5 | 6 | & img { 7 | height: 100%; 8 | border-radius: $border-radius-circle; 9 | border: $border-library-cover; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Elements/Common/MenuIcon.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { RiMenu4Fill } from "react-icons/ri"; 3 | 4 | function MenuIcon({ uiState, setUiState }) { 5 | const navHandler = () => { 6 | setUiState({ ...uiState, aboutShown: true }); 7 | }; 8 | return ; 9 | } 10 | 11 | export default MenuIcon; 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/Styles/elements/_song-info-title.scss: -------------------------------------------------------------------------------- 1 | .song-info { 2 | &__title { 3 | font-size: $font-size-song-info-title; 4 | text-align: center; 5 | font-weight: $font-weight-song-info-title; 6 | } 7 | } 8 | 9 | @media only screen and (min-width: 900px) { 10 | .song-info { 11 | &__title { 12 | font-size: $font-size-song-info-title * 1.5; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Elements/About/AboutHeaderCloseIcon.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { RiCloseFill } from "react-icons/ri"; 3 | 4 | function AboutHeaderCloseIcon({ uiState, setUiState }) { 5 | const aboutCloseHandler = () => { 6 | setUiState({ ...uiState, aboutShown: false }); 7 | }; 8 | return ; 9 | } 10 | 11 | export default AboutHeaderCloseIcon; 12 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/Styles/components/_about-socials.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | &-socials { 3 | display: flex; 4 | flex-direction: column; 5 | gap: 2rem; 6 | 7 | &-group { 8 | display: flex; 9 | gap: 2rem; 10 | align-items: center; 11 | } 12 | &-icon { 13 | font-size: 1.8rem; 14 | } 15 | &-text { 16 | font-size: 1.5rem; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Elements/Main/SongInfoArtist.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import colors from "../../Utils/Colors"; 3 | 4 | function SongInfoArtist({ songState }) { 5 | return ( 6 |

10 | {songState.currentSong[0].artist} 11 |

12 | ); 13 | } 14 | 15 | export default SongInfoArtist; 16 | -------------------------------------------------------------------------------- /src/Styles/elements/_song-info-artist.scss: -------------------------------------------------------------------------------- 1 | .song-info { 2 | &__artist { 3 | font-size: $font-size-song-info-artist; 4 | text-align: center; 5 | font-weight: $font-weight-song-info-artist; 6 | transition: color 300ms; 7 | } 8 | } 9 | @media only screen and (min-width: 900px) { 10 | .song-info { 11 | &__artist { 12 | font-size: $font-size-song-info-artist * 1.25; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Components/Common/MenuHeader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import MenuTitle from "../../Elements/Common/MenuTitle"; 3 | import MenuIcon from "../../Elements/Common/MenuIcon"; 4 | function MenuHeader({ uiState, setUiState }) { 5 | return ( 6 | 10 | ); 11 | } 12 | 13 | export default MenuHeader; 14 | -------------------------------------------------------------------------------- /src/Components/Main/SongInfo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import SongInfoTitle from "../../Elements/Main/SongInfoTitle"; 3 | import SongInfoArtist from "../../Elements/Main/SongInfoArtist"; 4 | function SongInfo({ songState }) { 5 | return ( 6 |
7 | 8 | 9 |
10 | ); 11 | } 12 | 13 | export default SongInfo; 14 | -------------------------------------------------------------------------------- /src/Utils/Colors.js: -------------------------------------------------------------------------------- 1 | const colors = { 2 | darkgrey: "#212529", 3 | grey: "#adb5bd", 4 | white: "#faf9f9", 5 | red: "#FF7366", 6 | orange: "#FF7744", 7 | yellow: "#FFAB00", 8 | green: "#43A047", 9 | cyan: "#00BCD4", 10 | blue: "#79B0FB", 11 | purple: "#BF8CFC", 12 | pink: "#FB79B8", 13 | teal: "#00BFA5", 14 | coral: "#F58770", 15 | brown: "#CCA760", 16 | magenta: "#FB79F2", 17 | }; 18 | 19 | export default colors; 20 | -------------------------------------------------------------------------------- /src/Elements/Library/LibraryHeaderCloseIcon.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { RiCloseFill } from "react-icons/ri"; 3 | 4 | function MenuIcon({ uiState, setUiState }) { 5 | const libraryCloseHandler = () => { 6 | setUiState({ ...uiState, libraryShown: false }); 7 | }; 8 | return ( 9 | 13 | ); 14 | } 15 | 16 | export default MenuIcon; 17 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | // console.log("Hello World"); 2 | let j = 0; 3 | let currentSongIndex = 0; 4 | let totalSongs = 16; 5 | 6 | // next 7 | // for (j = 0; j < 20; j++) { 8 | // console.log(((totalSongs + currentSongIndex) % totalSongs) + 1); 9 | // currentSongIndex++; 10 | // } 11 | 12 | currentSongIndex = 0; 13 | // Prev 14 | for (j = 0; j < 20; j++) { 15 | currentSongIndex--; 16 | console.log(totalSongs + (currentSongIndex % totalSongs) - 1); 17 | } 18 | 19 | /* 20 | 21 | 15 = 15 - 0 + 1 22 | 23 | */ 24 | -------------------------------------------------------------------------------- /src/Components/About/AboutHeader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import AboutHeaderTitle from "../../Elements/About/AboutHeaderTitle"; 3 | import AboutHeaderCloseIcon from "../../Elements/About/AboutHeaderCloseIcon"; 4 | function MenuHeader({ uiState, setUiState }) { 5 | return ( 6 | 10 | ); 11 | } 12 | 13 | export default MenuHeader; 14 | -------------------------------------------------------------------------------- /src/Components/Library/LibraryHeader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import LibraryHeaderTitle from "../../Elements/Library/LibraryHeaderTitle"; 3 | import LibraryHeaderCloseIcon from "../../Elements/Library/LibraryHeaderCloseIcon"; 4 | function MenuHeader({ uiState, setUiState }) { 5 | return ( 6 | 10 | ); 11 | } 12 | 13 | export default MenuHeader; 14 | -------------------------------------------------------------------------------- /src/Styles/elements/_artwork.scss: -------------------------------------------------------------------------------- 1 | .artwork { 2 | height: $height-artwork; 3 | width: $height-artwork; 4 | border: $border-artwork; 5 | border-radius: $border-radius-circle; 6 | overflow: hidden; 7 | transition: border 300ms; 8 | // box-shadow: $shadow-library-sidebar; 9 | 10 | img { 11 | height: 100%; 12 | border-radius: $border-radius-circle; 13 | } 14 | } 15 | 16 | @media only screen and (min-width: 900px) { 17 | .artwork { 18 | height: $height-artwork * 1.25; 19 | width: $height-artwork * 1.25; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Styles/base/_base.scss: -------------------------------------------------------------------------------- 1 | // CSS Reset 2 | * { 3 | padding: 0; 4 | margin: 0; 5 | box-sizing: border-box; 6 | outline: none; 7 | scroll-behavior: smooth; 8 | 9 | &::selection { 10 | background-color: #0000; 11 | } 12 | } 13 | 14 | body { 15 | font-family: $poppins; 16 | font-size: $font-size-body; 17 | // background-color: $color-darkmode; 18 | background-position: center; 19 | background-size: cover; 20 | background-repeat: no-repeat; 21 | text-shadow: 0px 0px 15px #c5c5c53b; 22 | } 23 | 24 | :root { 25 | font-size: $font-size-root; 26 | } 27 | -------------------------------------------------------------------------------- /src/Styles/elements/_player-control-icon.scss: -------------------------------------------------------------------------------- 1 | .player__control { 2 | &--play-button { 3 | border-radius: $border-radius-circle; 4 | height: $space-lg; 5 | width: $space-lg; 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | cursor: pointer; 10 | transition: background 300ms; 11 | } 12 | 13 | &-icon { 14 | cursor: pointer; 15 | font-size: $font-size-player-icon; 16 | &--white { 17 | color: $color-white; 18 | font-size: $font-size-player-icon * 1.5; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Elements/About/AboutButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import colors from "../../Utils/Colors"; 3 | import gradients from "../../Utils/Gradients"; 4 | import shadow from "../../Utils/Shadows"; 5 | 6 | function AboutButton() { 7 | return ( 8 | 16 | View Portfolio 17 | 18 | ); 19 | } 20 | 21 | export default AboutButton; 22 | -------------------------------------------------------------------------------- /src/Styles/components/_library-list-item.scss: -------------------------------------------------------------------------------- 1 | .library { 2 | &__list { 3 | &-item { 4 | display: flex; 5 | gap: 2rem; 6 | align-items: center; 7 | padding: 2rem; 8 | 9 | &:hover { 10 | background-color: #ffffff13; 11 | } 12 | } 13 | } 14 | &__song-column { 15 | display: flex; 16 | flex-direction: column; 17 | gap: 1rem; 18 | flex: 1; 19 | } 20 | } 21 | 22 | .active-song { 23 | background-color: #ffffff3a; 24 | 25 | &:hover { 26 | background-color: #ffffff3a; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Elements/Library/LibrarySongCover.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import colors from "../../Utils/Colors"; 3 | import shadow from "../../Utils/Shadows"; 4 | 5 | function LibrarySongCover({ song }) { 6 | return ( 7 |
8 | Artwork 16 |
17 | ); 18 | } 19 | 20 | export default LibrarySongCover; 21 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ChillyPopper - Minimal Music Player", 3 | "short_name": "ChillyPopper", 4 | "theme_color": "#ef476f", 5 | "background_color": "#353535", 6 | "display": "standalone", 7 | "orientation": "any", 8 | "icons": [ 9 | { 10 | "src": "favicon.ico", 11 | "sizes": "64x64 32x32 24x24 16x16", 12 | "type": "image/x-icon" 13 | }, 14 | { 15 | "src": "logo192.png", 16 | "type": "image/png", 17 | "sizes": "192x192" 18 | }, 19 | { 20 | "src": "logo512.png", 21 | "type": "image/png", 22 | "sizes": "512x512" 23 | } 24 | ], 25 | "start_url": "/", 26 | "scope": "/" 27 | } 28 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import * as serviceWorkerRegistration from "./serviceWorkerRegistration"; 5 | // import reportWebVitals from "./reportWebVitals"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root") 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://cra.link/PWA 17 | serviceWorkerRegistration.register(); 18 | 19 | // If you want to start measuring performance in your app, pass a function 20 | // to log results (for example: reportWebVitals(console.log)) 21 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 22 | // reportWebVitals(); 23 | -------------------------------------------------------------------------------- /src/Components/PlayerInterface/Player.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PlayerControl from "../Main/PlayerControl"; 3 | import SeekControl from "../Main/SeekControl"; 4 | function Player({ 5 | uiState, 6 | setUiState, 7 | songState, 8 | setSongState, 9 | audioRef, 10 | seekWidth, 11 | }) { 12 | return ( 13 |
14 | 22 | 29 |
30 | ); 31 | } 32 | 33 | export default Player; 34 | -------------------------------------------------------------------------------- /src/Styles/layouts/_about.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100%; 7 | // background-color: #0007; 8 | backdrop-filter: blur(5rem); 9 | transition: transform 500ms; 10 | transition-timing-function: cubic-bezier(0.45, 0, 0.53, 0.97); 11 | overflow-y: scroll; 12 | scrollbar-width: thin; 13 | scrollbar-color: #7777 $color-grey-transparent; 14 | &::-webkit-scrollbar { 15 | width: 1rem; 16 | } 17 | &::-webkit-scrollbar-track { 18 | background: $color-grey-transparent; 19 | border-radius: 10rem; 20 | } 21 | 22 | &::-webkit-scrollbar-thumb { 23 | background: #7777; 24 | border-radius: 10rem; 25 | } 26 | 27 | &__wrapper { 28 | max-width: 80rem; 29 | margin: 0 auto; 30 | display: flex; 31 | flex-direction: column; 32 | gap: 4rem; 33 | padding: 2rem; 34 | } 35 | 36 | &--hidden { 37 | transform: translatey(-100%); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Layouts/Library.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import LibraryHeader from "../Components/Library/LibraryHeader"; 3 | import LibraryListItem from "../Components/Library/LibraryListItem"; 4 | 5 | function Library({ 6 | uiState, 7 | setUiState, 8 | setSongState, 9 | songState, 10 | songData, 11 | audioRef, 12 | }) { 13 | return ( 14 |
19 | 20 |
21 | {songData.map((song) => ( 22 | 28 | ))} 29 |
30 |
31 | ); 32 | } 33 | 34 | export default Library; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Priyanshu Bharti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Elements/Main/Artwork.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import colors from "../../Utils/Colors"; 3 | import shadow from "../../Utils/Shadows"; 4 | 5 | function Artwork({ uiState, songState }) { 6 | const currentPalette = songState.currentSong[0].palette; 7 | 8 | return ( 9 |
21 | Album Art 32 |
33 | ); 34 | } 35 | 36 | export default Artwork; 37 | -------------------------------------------------------------------------------- /src/Styles/app.scss: -------------------------------------------------------------------------------- 1 | // Common 2 | @import "common/variables"; 3 | @import "common/animations"; 4 | 5 | // Fonts 6 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"); 7 | 8 | // Base 9 | @import "base/base"; 10 | 11 | // Layouts 12 | @import "layouts/home"; 13 | @import "layouts/library"; 14 | @import "layouts/about"; 15 | 16 | // Elements 17 | @import "elements/menu-title"; 18 | @import "elements/menu-icon"; 19 | @import "elements/artwork"; 20 | @import "elements/song-info-artist"; 21 | @import "elements/song-info-title"; 22 | @import "elements/player-duration"; 23 | @import "elements/player-seek-bar"; 24 | @import "elements/player-control-icon"; 25 | @import "elements/library-song-cover"; 26 | @import "elements/library-song-artist"; 27 | @import "elements/library-close-icon"; 28 | @import "elements/about-button"; 29 | @import "elements/about-headline"; 30 | @import "elements/about-img"; 31 | @import "elements/about-question"; 32 | 33 | // Components 34 | @import "components/nav-header"; 35 | @import "components/song-info"; 36 | @import "components/player-seek-controls"; 37 | @import "components/player-control"; 38 | @import "components/player"; 39 | @import "components/library-list-item"; 40 | @import "components/about-socials"; 41 | -------------------------------------------------------------------------------- /src/Utils/Gradients.js: -------------------------------------------------------------------------------- 1 | const gradients = { 2 | light: "linear-gradient(135deg, #e6e9f0 0%, #eef1f5 100%)", 3 | dark: "linear-gradient(135deg, #434343 0%, black 100%)", 4 | red: "linear-gradient(135deg, hsla(333, 100%, 53%, 1) 0%, hsla(33, 94%, 57%, 1) 100%)", 5 | orange: "linear-gradient(135deg, hsla(42, 93%, 57%, 1) 0%, hsla(358, 78%, 62%, 1) 100%)", 6 | yellow: "linear-gradient(135deg, hsla(33, 100%, 53%, 1) 0%, hsla(58, 100%, 68%, 1) 100%)", 7 | green: "linear-gradient(135deg, hsla(59, 86%, 68%, 1) 0%, hsla(134, 36%, 53%, 1) 100%)", 8 | cyan: "linear-gradient(135deg, hsla(206, 91%, 66%, 1) 0%, hsla(190, 90%, 51%, 1) 100%)", 9 | blue: "linear-gradient(135deg, #6a11cb 0%, #2575fc 100%)", 10 | purple: "linear-gradient(135deg, hsla(238, 100%, 71%, 1) 0%, hsla(295, 100%, 84%, 1) 100%)", 11 | pink: "linear-gradient(135deg, #b8cbb8 0%, #b8cbb8 0%, #b465da 0%, #cf6cc9 33%, #ee609c 66%, #ee609c 100%)", 12 | teal: "linear-gradient(135deg, hsla(173, 89%, 70%, 1) 0%, hsla(196, 68%, 38%, 1) 100%)", 13 | coral: "linear-gradient(135deg, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%)", 14 | brown: "linear-gradient(to top, #c79081 0%, #dfa579 100%)", 15 | magenta: 16 | "linear-gradient(135deg, hsla(333, 100%, 53%, 1) 0%, hsla(238, 100%, 71%, 1) 100%)", 17 | }; 18 | 19 | export default gradients; 20 | -------------------------------------------------------------------------------- /src/Styles/elements/_player-seek-bar.scss: -------------------------------------------------------------------------------- 1 | .player { 2 | &__seek-bar { 3 | width: 100%; 4 | &--wrapper { 5 | background-color: $color-grey-transparent; 6 | height: $height-seek-bar; 7 | border-radius: 50rem; 8 | position: relative; 9 | flex: 1; 10 | } 11 | appearance: none; 12 | background-color: transparent; 13 | &::-webkit-slider-thumb { 14 | appearance: none; 15 | z-index: 10; 16 | height: $height-seek-bar-thumb; 17 | width: $height-seek-bar-thumb; 18 | background-color: $color-white; 19 | box-shadow: $shadow-seek-thumb; 20 | border-radius: $border-radius-circle; 21 | transform: translateY(-25%); 22 | } 23 | 24 | &::-moz-range-thumb { 25 | appearance: none; 26 | z-index: 10; 27 | height: $height-seek-bar-thumb; 28 | width: $height-seek-bar-thumb; 29 | background-color: $color-white; 30 | box-shadow: $shadow-seek-thumb; 31 | border-radius: $border-radius-circle; 32 | border: none; 33 | transform: translateY(-25%); 34 | } 35 | 36 | &--gradient { 37 | max-width: 100%; 38 | height: $height-seek-bar; 39 | position: absolute; 40 | top: 0; 41 | border-radius: 50rem; 42 | } 43 | 44 | flex: 1; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Styles/layouts/_library.scss: -------------------------------------------------------------------------------- 1 | .library { 2 | position: fixed; 3 | top: 0; 4 | display: flex; 5 | width: 100%; 6 | height: 100%; 7 | flex-direction: column; 8 | transition: transform 500ms; 9 | transition-timing-function: cubic-bezier(0.45, 0, 0.53, 0.97); 10 | // background-color: #353535cc; 11 | backdrop-filter: blur(3rem); 12 | &--hidden { 13 | transform: translateX(-100%); 14 | } 15 | 16 | &__wrapper { 17 | display: flex; 18 | flex-direction: column; 19 | overflow-y: scroll; 20 | scrollbar-width: thin; 21 | scrollbar-color: #7777 $color-grey-transparent; 22 | &::-webkit-scrollbar { 23 | width: 1rem; 24 | } 25 | &::-webkit-scrollbar-track { 26 | background: $color-grey-transparent; 27 | border-radius: 10rem; 28 | } 29 | 30 | &::-webkit-scrollbar-thumb { 31 | background: #7777; 32 | border-radius: 10rem; 33 | } 34 | } 35 | } 36 | 37 | @media only screen and (min-width: 900px) { 38 | .library { 39 | position: relative; 40 | backdrop-filter: unset; 41 | height: 100%; 42 | 43 | .nav__header { 44 | display: none; 45 | } 46 | &__menu { 47 | &__icon { 48 | display: none; 49 | } 50 | } 51 | &__wrapper { 52 | flex: 1; 53 | } 54 | } 55 | 56 | .disabled-on-desktop { 57 | color: rgba(139, 139, 139, 0.596); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Components/Main/SeekControl.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PlayerDuration from "../../Elements/Main/PlayerDuration"; 3 | import PlayerSeekBar from "../../Elements/Main/PlayerSeekBar"; 4 | 5 | function SeekControl({ songState, setSongState, audioRef, seekWidth }) { 6 | const getTime = (time) => { 7 | return ( 8 | Math.floor(time / 60) + 9 | ":" + 10 | ("0" + Math.floor(time % 60)).slice(-2) 11 | // get the time and divide it by 60 - 155/60 = 2.59 12 | // Floor the value - 2 13 | // append ":" to the number from previous step 14 | // divide the time by 60 and get the remainder - 155 % 60 (remainder = 35) 15 | // Now floor this remainder to obtain a smaller value - getting rid of decimals 16 | // prepend "0" to the number obtained from previous step 17 | // slice the number to get only the last 2 digits 18 | ); 19 | }; 20 | return ( 21 |
22 | 23 | 29 | 36 |
37 | ); 38 | } 39 | 40 | export default SeekControl; 41 | -------------------------------------------------------------------------------- /src/Elements/Main/PlayerSeekBar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import colors from "../../Utils/Colors"; 3 | import gradients from "../../Utils/Gradients"; 4 | import shadow from "../../Utils/Shadows"; 5 | 6 | function PlayerSeekBar({ songState, audioRef, setSongState }) { 7 | const currentPalette = songState.currentSong[0].palette; 8 | 9 | const playerSeekHandler = (e) => { 10 | //Changing the value of the duration and elapsed 11 | const value = e.target.value; 12 | audioRef.current.currentTime = value; 13 | setSongState({ 14 | ...songState, 15 | elapsed: value, 16 | }); 17 | }; 18 | 19 | return ( 20 |
21 |
35 | 44 |
45 | ); 46 | } 47 | 48 | export default PlayerSeekBar; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chilly-popper", 3 | "homepage": ".", 4 | "version": "0.1.0", 5 | "private": true, 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^5.14.1", 8 | "@testing-library/react": "^11.2.7", 9 | "@testing-library/user-event": "^12.8.3", 10 | "node-sass": "^6.0.1", 11 | "react": "^17.0.2", 12 | "react-dom": "^17.0.2", 13 | "react-icons": "^4.2.0", 14 | "react-scripts": "4.0.3", 15 | "uuid": "^8.3.2", 16 | "web-vitals": "^0.2.4", 17 | "workbox-background-sync": "^5.1.4", 18 | "workbox-broadcast-update": "^5.1.4", 19 | "workbox-cacheable-response": "^5.1.4", 20 | "workbox-core": "^5.1.4", 21 | "workbox-expiration": "^5.1.4", 22 | "workbox-google-analytics": "^5.1.4", 23 | "workbox-navigation-preload": "^5.1.4", 24 | "workbox-precaching": "^5.1.4", 25 | "workbox-range-requests": "^5.1.4", 26 | "workbox-routing": "^5.1.4", 27 | "workbox-strategies": "^5.1.4", 28 | "workbox-streams": "^5.1.4" 29 | }, 30 | "scripts": { 31 | "start": "react-scripts start", 32 | "build": "react-scripts build", 33 | "test": "react-scripts test", 34 | "eject": "react-scripts eject" 35 | }, 36 | "eslintConfig": { 37 | "extends": [ 38 | "react-app", 39 | "react-app/jest" 40 | ] 41 | }, 42 | "browserslist": { 43 | "production": [ 44 | ">0.2%", 45 | "not dead", 46 | "not op_mini all" 47 | ], 48 | "development": [ 49 | "last 1 chrome version", 50 | "last 1 firefox version", 51 | "last 1 safari version" 52 | ] 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | ChillyPopper 26 | 27 | 28 | 29 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/Components/Library/LibraryListItem.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import songData from "../../Data/SongData"; 3 | import LibrarySongArtist from "../../Elements/Library/LibrarySongArtist"; 4 | import LibrarySongCover from "../../Elements/Library/LibrarySongCover"; 5 | import LibrarySongTitle from "../../Elements/Library/LibrarySongTitle"; 6 | 7 | function LibraryListItem({ song, setSongState, songState, audioRef }) { 8 | // console.log(song.id === songState.currentSong[0].id); 9 | // currentSong: [songData[(currentIndex + 1) % songData.length]], 10 | 11 | const changeCurrentSongHandler = () => { 12 | setTimeout(() => { 13 | setSongState({ 14 | ...songState, 15 | currentSong: [songData[songData.findIndex((s) => s === song)]], 16 | }); 17 | console.log(songState.isPlaying); 18 | if (songState.isPlaying) { 19 | const playPromise = audioRef.current.play(); 20 | console.log(playPromise); 21 | if (playPromise !== undefined) { 22 | console.log("undefined"); 23 | playPromise.then((audio) => { 24 | audioRef.current.play(); 25 | }); 26 | } 27 | } 28 | }, 150); 29 | }; 30 | return ( 31 |
37 | 38 |
39 | 40 | 41 |
42 |
43 | ); 44 | } 45 | 46 | export default LibraryListItem; 47 | -------------------------------------------------------------------------------- /src/Elements/Main/PlayerPlayButton.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { RiPlayFill } from "react-icons/ri"; 3 | import { IoIosPause } from "react-icons/io"; 4 | import shadow from "../../Utils/Shadows"; 5 | import colors from "../../Utils/Colors"; 6 | import gradients from "../../Utils/Gradients"; 7 | 8 | function PlayerPlayButton({ 9 | uiState, 10 | setUiState, 11 | songState, 12 | audioRef, 13 | setSongState, 14 | }) { 15 | const currentPalette = songState.currentSong[0].palette; 16 | const playPauseHandler = () => { 17 | setUiState({ ...uiState, songPlaying: !uiState.songPlaying }); 18 | if (uiState.songPlaying === true) { 19 | audioRef.current.pause(); 20 | setSongState({ ...songState, isPlaying: false }); 21 | } else { 22 | audioRef.current.play(); 23 | setSongState({ ...songState, isPlaying: true }); 24 | } 25 | }; 26 | 27 | const PlayPauseButton = () => { 28 | if (uiState.songPlaying) { 29 | return ( 30 | 31 | ); 32 | } else { 33 | return ( 34 | 35 | ); 36 | } 37 | }; 38 | 39 | return ( 40 |
54 | 55 |
56 | ); 57 | } 58 | 59 | export default PlayerPlayButton; 60 | -------------------------------------------------------------------------------- /src/Styles/layouts/_home.scss: -------------------------------------------------------------------------------- 1 | .app { 2 | &__wrapper { 3 | display: grid; 4 | height: 100vh; 5 | grid-template-columns: 1fr; 6 | grid-template-rows: auto minmax(auto, 1fr) auto minmax(auto, 1fr); 7 | gap: clamp(1rem, 5vw, 3rem); 8 | transition: background 300ms, color 300ms, backdrop-filter 100ms; 9 | transition-timing-function: cubic-bezier(0.45, 0.01, 0.69, 1); 10 | 11 | .nav__header { 12 | grid-row: 1/2; 13 | } 14 | 15 | .artwork { 16 | grid-row: 2/3; 17 | } 18 | 19 | .song-info { 20 | grid-row: 3/4; 21 | } 22 | 23 | .player { 24 | grid-row: 4/5; 25 | } 26 | 27 | .artwork, 28 | .song-info, 29 | .player { 30 | place-self: center; 31 | } 32 | } 33 | } 34 | 35 | .dark-mode { 36 | background: linear-gradient(135deg, #313131cb 0%, #000000cb 100%); 37 | color: $color-white; 38 | } 39 | .light-mode { 40 | background: linear-gradient(135deg, #e6e9f0c5 0%, #eef1f5c5 100%); 41 | color: $color-darkmode; 42 | } 43 | 44 | // Grid Layout for the desktop 45 | @media only screen and (min-width: 900px) { 46 | body { 47 | overflow-y: scroll; 48 | scrollbar-width: thin; 49 | scrollbar-color: #7777 $color-grey-transparent; 50 | &::-webkit-scrollbar { 51 | width: 1rem; 52 | } 53 | &::-webkit-scrollbar-track { 54 | background: $color-grey-transparent; 55 | border-radius: 10rem; 56 | } 57 | 58 | &::-webkit-scrollbar-thumb { 59 | background: #7777; 60 | border-radius: 10rem; 61 | } 62 | } 63 | .app { 64 | &__wrapper { 65 | grid-template-columns: minmax(35rem, 1fr) 3fr; 66 | // grid-template-rows: 10% 30% 30% 20%; 67 | 68 | .nav__header { 69 | grid-column: 1/3; 70 | } 71 | 72 | .library { 73 | grid-column: 1/2; 74 | grid-row: 2/5; 75 | transform: translateX(0); 76 | } 77 | 78 | .player, 79 | .artwork, 80 | .song-info { 81 | grid-column: 2/3; 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Styles/common/_variables.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------- FONT FAMILY ------------------------------ */ 2 | $poppins: "Poppins", sans-serif; 3 | 4 | /* -------------------------------- FONT SIZE ------------------------------- */ 5 | // Font size Body 6 | $font-size-root: 10px; 7 | $font-size-reference: 1rem; 8 | $font-size-body: $font-size-reference * 1.6; 9 | // Nav Menu 10 | $font-size-menu-title: $font-size-reference * 2.2; // Desktop needs to be big 11 | $font-size-menu-icon: $font-size-menu-title; 12 | // Nav Options 13 | $font-size-nav-option-title: $font-size-reference * 1.8; 14 | $font-size-nav-option-icon: $font-size-nav-option-title + 0.2rem; 15 | // Library 16 | $font-size-library-song-title: $font-size-reference * 1.6; 17 | $font-size-library-song-artist: $font-size-reference * 1.4; 18 | // Player Icons 19 | $font-size-player-icon: $font-size-reference * 2; 20 | $font-size-time-duration: $font-size-reference * 1.3; 21 | // Song Info 22 | $font-size-song-info-title: $font-size-reference * 2; 23 | $font-size-song-info-artist: $font-size-reference * 1.4; 24 | 25 | /* ------------------------------- FONT WEIGHT ------------------------------ */ 26 | $font-weight-song-info-title: 600; 27 | $font-weight-song-info-artist: 400; 28 | $font-weight-player-duration: 300; 29 | 30 | /* --------------------------------- COLORS --------------------------------- */ 31 | $color-darkmode: #353535; 32 | $color-darkmode-transparent: #3535359c; 33 | $color-grey: #adb5bd; 34 | $color-darkgrey: #797979; 35 | $color-white: #fafafa; 36 | $color-grey-transparent: #77777745; 37 | $color-lightgrey-transparent: #8f8f8f36; 38 | $color-shadow-black: #0000003d; 39 | 40 | /* --------------------------------- BORDERS -------------------------------- */ 41 | // Artwork Border 42 | $border-artwork: 1rem solid $color-white; 43 | $border-artwork-dark: 1rem solid $color-lightgrey-transparent; 44 | // Library Covers 45 | $border-library-cover: 0.6rem solid $color-white; 46 | // Border Dividers 47 | $border-item-divider: 0.1rem solid $color-grey-transparent; 48 | 49 | /* ------------------------------ BORDER RADII ------------------------------ */ 50 | // Circle 51 | $border-radius-circle: 100%; 52 | // Rounded edges 53 | $border-radius-rounded: 10rem; 54 | 55 | /* --------------------------------- SPACING -------------------------------- */ 56 | // Used in padding and margin 57 | $space-xsm: 1rem; 58 | $space-sm: 2rem; 59 | $space-md: 3rem; 60 | $space-lg: 4rem; 61 | $space-xlg: 6rem; 62 | 63 | /* --------------------------------- SHADOWS -------------------------------- */ 64 | $shadow-seek-thumb: 0px 0px 12px 0px $color-shadow-black; 65 | $shadow-seek-bar: 0px 0px 6px 0px $color-shadow-black; 66 | $shadow-library-sidebar: 4px 0px 25px 0px $color-shadow-black; 67 | $shadow-nav-menu: 0px 4px 25px 0px $color-shadow-black; 68 | 69 | /* ---------------------------- RESPONSIVE CLAMPS --------------------------- */ 70 | $clamp-player-seek-control-width: clamp(28rem, 50vw, 90rem); 71 | $clamp-song-info-gap: clamp(0.5rem, 3vw, 3rem); 72 | 73 | /* --------------------------------- HEIGHTS -------------------------------- */ 74 | $height-seek-bar: 1rem; 75 | $height-seek-bar-thumb: 2rem; 76 | $height-artwork: 24rem; 77 | -------------------------------------------------------------------------------- /src/service-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-globals */ 2 | 3 | // This service worker can be customized! 4 | // See https://developers.google.com/web/tools/workbox/modules 5 | // for the list of available Workbox modules, or add any other 6 | // code you'd like. 7 | // You can also remove this file if you'd prefer not to use a 8 | // service worker, and the Workbox build step will be skipped. 9 | 10 | import { clientsClaim } from "workbox-core"; 11 | import { ExpirationPlugin } from "workbox-expiration"; 12 | import { precacheAndRoute, createHandlerBoundToURL } from "workbox-precaching"; 13 | import { registerRoute } from "workbox-routing"; 14 | import { StaleWhileRevalidate } from "workbox-strategies"; 15 | 16 | clientsClaim(); 17 | 18 | // Precache all of the assets generated by your build process. 19 | // Their URLs are injected into the manifest variable below. 20 | // This variable must be present somewhere in your service worker file, 21 | // even if you decide not to use precaching. See https://cra.link/PWA 22 | precacheAndRoute(self.__WB_MANIFEST); 23 | 24 | // Set up App Shell-style routing, so that all navigation requests 25 | // are fulfilled with your index.html shell. Learn more at 26 | // https://developers.google.com/web/fundamentals/architecture/app-shell 27 | const fileExtensionRegexp = new RegExp("/[^/?]+\\.[^/]+$"); 28 | registerRoute( 29 | // Return false to exempt requests from being fulfilled by index.html. 30 | ({ request, url }) => { 31 | // If this isn't a navigation, skip. 32 | if (request.mode !== "navigate") { 33 | return false; 34 | } // If this is a URL that starts with /_, skip. 35 | 36 | if (url.pathname.startsWith("/_")) { 37 | return false; 38 | } // If this looks like a URL for a resource, because it contains // a file extension, skip. 39 | 40 | if (url.pathname.match(fileExtensionRegexp)) { 41 | return false; 42 | } // Return true to signal that we want to use the handler. 43 | 44 | return true; 45 | }, 46 | createHandlerBoundToURL(process.env.PUBLIC_URL + "/index.html") 47 | ); 48 | 49 | // An example runtime caching route for requests that aren't handled by the 50 | // precache, in this case same-origin .png requests like those from in public/ 51 | registerRoute( 52 | // Add in any other file extensions or routing criteria as needed. 53 | ({ url }) => 54 | url.origin === self.location.origin && url.pathname.endsWith(".png"), // Customize this strategy as needed, e.g., by changing to CacheFirst. 55 | new StaleWhileRevalidate({ 56 | cacheName: "images", 57 | plugins: [ 58 | // Ensure that once this runtime cache reaches a maximum size the 59 | // least-recently used images are removed. 60 | new ExpirationPlugin({ maxEntries: 50 }), 61 | ], 62 | }) 63 | ); 64 | 65 | // This allows the web app to trigger skipWaiting via 66 | // registration.waiting.postMessage({type: 'SKIP_WAITING'}) 67 | self.addEventListener("message", (event) => { 68 | if (event.data && event.data.type === "SKIP_WAITING") { 69 | self.skipWaiting(); 70 | } 71 | }); 72 | 73 | // Any other custom service worker logic can go here. 74 | -------------------------------------------------------------------------------- /src/Layouts/About.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import AboutHeader from "../Components/About/AboutHeader"; 3 | import AboutButton from "../Elements/About/AboutButton"; 4 | import AboutHeadline from "../Elements/About/AboutHeadline"; 5 | import AboutQuestionTitle from "../Elements/About/AboutQuestionTitle"; 6 | import AboutQuestionAnswer from "../Elements/About/AboutQuestionAnswer"; 7 | import AboutImg from "../Elements/About/AboutImg"; 8 | import { RiInstagramLine, RiLinkedinBoxFill, RiMailLine } from "react-icons/ri"; 9 | 10 | function About({ uiState, setUiState }) { 11 | let questionOne = "What even is ChillyPopper?"; 12 | let answerOne = 13 | "In simple words, it is a music player without ads or distractions that allows you to listen to chillpop music (hence the name...) while you’re coding or doing other work. It is just a weekend project and uses music available on Chillhop (details below)"; 14 | let questionTwo = "Who made this?"; 15 | let answerTwo = 16 | "This project was created by Priyanshu Bharti. A Computer Applications student, developer, and designer who likes creating awesome things that live on the internet! If you like what you just saw and would like to see more, then scroll below to check his socials!"; 17 | 18 | return ( 19 |
20 | 21 |
22 | {/* Need our headline */} 23 |
24 |

Hey There,

25 | 26 |
27 | {/* Need img */} 28 | 29 | {/* Need Questions */} 30 |
31 | 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 | {/* Second Headline */} 42 |
43 |

Priyanshu's

44 | 45 |
46 | 47 | {/* Socials */} 48 |
49 |
50 | 51 |

@_priyanshubharti

52 |
53 |
54 | 55 |

56 | /in/priyanshubharti 57 |

58 |
59 |
60 | 61 |

62 | priyanshub25dev@gmail.com 63 |

64 |
65 |
66 | 67 |
68 | {/* Third Headline */} 69 |
70 |

Like what you saw?

71 | 72 |
73 | {/* Portfolio Button */} 74 | 75 |
76 |
77 | ); 78 | } 79 | 80 | export default About; 81 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useState } from "react"; 2 | import "./Styles/app.scss"; 3 | import MenuHeader from "./Components/Common/MenuHeader"; 4 | import Artwork from "./Elements/Main/Artwork"; 5 | import SongInfo from "./Components/Main/SongInfo"; 6 | import Player from "./Components/PlayerInterface/Player"; 7 | import Library from "./Layouts/Library"; 8 | import About from "./Layouts/About"; 9 | import songData from "./Data/SongData"; 10 | 11 | function App() { 12 | // Detect if the user has dark mode turned on 13 | let userDarkModeApplied = window.matchMedia( 14 | "(prefers-color-scheme: dark)" 15 | ).matches; 16 | 17 | // UI Components State 18 | const [uiState, setUiState] = useState({ 19 | aboutShown: false, 20 | libraryShown: false, 21 | libraryPinned: false, 22 | darkMode: userDarkModeApplied ? true : false, 23 | coverSpinning: false, 24 | songPlaying: false, 25 | seekWidth: 0, 26 | }); 27 | // Song States 28 | const [songState, setSongState] = useState({ 29 | currentSong: [songData[0]], 30 | isPlaying: false, 31 | elapsed: 0, 32 | duration: 0, 33 | }); 34 | 35 | // Reference for the audio 36 | const audioRef = useRef(null); 37 | 38 | // Setting the background as the cover artwork 39 | document.body.style.backgroundImage = `url('${songState.currentSong[0].coverUrl}')`; 40 | 41 | const songEndHandler = async () => { 42 | let currentIndex = songData.findIndex( 43 | (song) => song === songState.currentSong[0] 44 | ); 45 | await setSongState({ 46 | ...songState, 47 | currentSong: [songData[(currentIndex + 1) % songData.length]], 48 | }); 49 | audioRef.current.play(); 50 | }; 51 | 52 | const songInfoHandler = (e) => { 53 | const elapsed = e.target.currentTime; 54 | const duration = e.target.duration; 55 | setSongState({ 56 | ...songState, 57 | duration: duration, 58 | elapsed: elapsed, 59 | }); 60 | }; 61 | 62 | return ( 63 |
80 | {/* The menu header only displays the menu options */} 81 | {/* It only needs access to isNavMenuShown, setNavMenuShown, */} 82 | 83 | 84 | 85 | 92 | 100 | 101 | 108 |
109 | ); 110 | } 111 | 112 | export default App; 113 | -------------------------------------------------------------------------------- /src/Components/Main/PlayerControl.js: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | import { 3 | RiPlayListLine, 4 | RiSunLine, 5 | RiMoonLine, 6 | RiSkipBackLine, 7 | RiSkipForwardLine, 8 | } from "react-icons/ri"; 9 | import songData from "../../Data/SongData"; 10 | import PlayerPlayButton from "../../Elements/Main/PlayerPlayButton"; 11 | 12 | function PlayerControl({ 13 | uiState, 14 | setUiState, 15 | songState, 16 | setSongState, 17 | audioRef, 18 | }) { 19 | let currentIndex = songData.findIndex( 20 | (song) => song === songState.currentSong[0] 21 | ); 22 | 23 | const previousSongHandler = () => { 24 | setTimeout(() => { 25 | if ((currentIndex - 1) % songData.length === -1) { 26 | setSongState({ 27 | ...songState, 28 | currentSong: [songData[songData.length - 1]], 29 | }); 30 | } else { 31 | setSongState({ 32 | ...songState, 33 | currentSong: [ 34 | songData[(currentIndex - 1) % songData.length], 35 | ], 36 | }); 37 | } 38 | if (songState.isPlaying) { 39 | const playPromise = audioRef.current.play(); 40 | if (playPromise !== undefined) { 41 | playPromise.then((audio) => { 42 | audioRef.current.play(); 43 | }); 44 | } 45 | } 46 | }, 300); 47 | }; 48 | 49 | const nextSongHandler = () => { 50 | setTimeout(() => { 51 | setSongState({ 52 | ...songState, 53 | currentSong: [songData[(currentIndex + 1) % songData.length]], 54 | }); 55 | if (songState.isPlaying) { 56 | audioRef.current.play(); 57 | } 58 | }, 150); 59 | }; 60 | 61 | const darkModeToggleHandler = () => { 62 | setUiState({ ...uiState, darkMode: !uiState.darkMode }); 63 | }; 64 | 65 | const libraryToggleHandler = (e) => { 66 | if (window.visualViewport.width < 900) { 67 | setUiState({ ...uiState, libraryShown: true }); 68 | console.log("changed"); 69 | } 70 | }; 71 | 72 | const songEndHandler = async () => { 73 | await setSongState({ 74 | ...songState, 75 | currentSong: [songData[(currentIndex + 1) % songData.length]], 76 | }); 77 | if (songState.currentSong[0].isPlaying) { 78 | const playPromise = audioRef.current.play(); 79 | if (playPromise !== undefined) { 80 | playPromise.then((audio) => audioRef.current.play()); 81 | } 82 | } 83 | }; 84 | 85 | const DarkModeButton = () => { 86 | if (!uiState.darkMode) { 87 | return ( 88 | 92 | ); 93 | } else { 94 | return ( 95 | 99 | ); 100 | } 101 | }; 102 | 103 | return ( 104 |
105 | 111 | 115 | 122 | 126 | 127 |
128 | ); 129 | } 130 | 131 | export default PlayerControl; 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 9 | 10 | 11 | 18 | 19 | 20 |
21 |
22 | 23 | Logo 24 | 25 | 26 |

Chillypopper - A React Music Player

27 | 28 |

29 | This is just a simple web app that plays some free to play chillpop lofi songs. 30 |
31 |
32 | View Demo 33 | · 34 | Report Bug 35 | · 36 | Request Feature 37 |

38 |
39 | 40 | 41 |
42 | Table of Contents 43 |
    44 |
  1. 45 | About The Project 46 | 49 |
  2. 50 |
  3. 51 | Getting Started 52 | 56 |
  4. 57 |
  5. Contributing
  6. 58 |
  7. License
  8. 59 |
  9. Contact
  10. 60 |
61 |
62 | 63 | 64 | 65 | ## About The Project 66 | 67 | [![Chillypopper][product-screenshot]](https://example.com) 68 | 69 | This was a weekend project that I created while learning the popular javascript framework, React. Feel free to fork this project and add your own stuff to it. 70 | 71 |

(back to top)

72 | 73 | ### Built With 74 | 75 | - [React.js](https://reactjs.org/) 76 | - [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) 77 | - [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) 78 | - [JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 79 | 80 |

(back to top)

81 | 82 | 83 | 84 | ## Getting Started 85 | 86 | Follow these steps to install the project on your local system. 87 | 88 | ### Prerequisites 89 | 90 | Clone the repository 91 | 92 | ```sh 93 | git clone https://github.com/priyanshu-bharti/chillypopper-react.git 94 | ``` 95 | 96 | ### Installation 97 | 98 | 1. Install the missing npm packages using the following command 99 | ```sh 100 | npm install 101 | ``` 102 | 2. Start the project from the root of the directory 103 | ```sh 104 | npm start 105 | ``` 106 | 107 |

(back to top)

108 | 109 | 110 | ## Contributing 111 | 112 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 113 | 114 | If you have a suggestion that would make this project better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". 115 | Don't forget to give the project a star! Thanks again! 116 | 117 | 1. Fork the Project 118 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 119 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 120 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 121 | 5. Open a Pull Request 122 | 123 |

(back to top)

124 | 125 | 126 | 127 | ## License 128 | 129 | Distributed under the MIT License. See `LICENSE.txt` for more information. 130 | 131 |

(back to top)

132 | 133 | 134 | 135 | ## Contact 136 | 137 | Priyanshu's Email - [priyanshub25@gmail.com](mailto:priyanshub25@gmail.com?subject=Github%20%7C%20%3CPlease%20enter%20your%20subject%20here%3E&body=%3CPlease%20Write%20your%20message%20here.%3E) - Click on this link to quickly send an email. 138 | 139 | Link: [Live Demo of the Web App](https://chillypopper.netlify.app) 140 | 141 |

(back to top)

142 | 143 | 144 |

(back to top)

145 | 146 | 147 | 148 | 149 | [contributors-shield]: https://img.shields.io/github/contributors/github_username/repo_name.svg?style=for-the-badge 150 | [contributors-url]: https://github.com/github_username/repo_name/graphs/contributors 151 | [forks-shield]: https://img.shields.io/github/forks/github_username/repo_name.svg?style=for-the-badge 152 | [forks-url]: https://github.com/github_username/repo_name/network/members 153 | [stars-shield]: https://img.shields.io/github/stars/github_username/repo_name.svg?style=for-the-badge 154 | [stars-url]: https://github.com/github_username/repo_name/stargazers 155 | [issues-shield]: https://img.shields.io/github/issues/github_username/repo_name.svg?style=for-the-badge 156 | [issues-url]: https://github.com/github_username/repo_name/issues 157 | [license-shield]: https://img.shields.io/github/license/github_username/repo_name.svg?style=for-the-badge 158 | [license-url]: https://github.com/github_username/repo_name/blob/master/LICENSE.txt 159 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 160 | [linkedin-url]: https://linkedin.com/in/linkedin_username 161 | [product-screenshot]: Cover.png 162 | -------------------------------------------------------------------------------- /src/serviceWorkerRegistration.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://cra.link/PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === "localhost" || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === "[::1]" || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener("load", () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | "This web app is being served cache-first by a service " + 46 | "worker. To learn more, visit https://cra.link/PWA" 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then((registration) => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === "installed") { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | "New content is available and will be used when all " + 74 | "tabs for this page are closed. See https://cra.link/PWA." 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log("Content is cached for offline use."); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch((error) => { 97 | console.error("Error during service worker registration:", error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { "Service-Worker": "script" }, 105 | }) 106 | .then((response) => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get("content-type"); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && 112 | contentType.indexOf("javascript") === -1) 113 | ) { 114 | // No service worker found. Probably a different app. Reload the page. 115 | navigator.serviceWorker.ready.then((registration) => { 116 | registration.unregister().then(() => { 117 | window.location.reload(); 118 | }); 119 | }); 120 | } else { 121 | // Service worker found. Proceed as normal. 122 | registerValidSW(swUrl, config); 123 | } 124 | }) 125 | .catch(() => { 126 | console.log( 127 | "No internet connection found. App is running in offline mode." 128 | ); 129 | }); 130 | } 131 | 132 | export function unregister() { 133 | if ("serviceWorker" in navigator) { 134 | navigator.serviceWorker.ready 135 | .then((registration) => { 136 | registration.unregister(); 137 | }) 138 | .catch((error) => { 139 | console.error(error.message); 140 | }); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Data/SongData.js: -------------------------------------------------------------------------------- 1 | import { v4 as uuidv4 } from "uuid"; 2 | 3 | const songData = [ 4 | { 5 | title: "Glaciar", 6 | artist: "Juan Rios", 7 | coverUrl: 8 | "https://chillhop.com/wp-content/uploads/2021/07/4163ebb931e06d4ee8eb184295c0246d4a5055f7-1024x1024.jpg", 9 | thumbUrl: 10 | "https://chillhop.com/wp-content/uploads/2021/07/4163ebb931e06d4ee8eb184295c0246d4a5055f7-150x150.jpg", 11 | audio: "https://mp3.chillhop.com/serve.php/?mp3=21648", 12 | palette: "coral", 13 | id: uuidv4(), 14 | }, 15 | { 16 | title: "What If I Told You", 17 | artist: "Juan Rios", 18 | coverUrl: 19 | "https://chillhop.com/wp-content/uploads/2021/07/935da7886600df5eeb2d3b13b12cf27ee8c6c700-1024x1024.jpg", 20 | thumbUrl: 21 | "https://chillhop.com/wp-content/uploads/2021/07/935da7886600df5eeb2d3b13b12cf27ee8c6c700-150x150.jpg", 22 | audio: "https://mp3.chillhop.com/serve.php/?mp3=21649", 23 | palette: "yellow", 24 | id: uuidv4(), 25 | }, 26 | { 27 | title: "Toofpick", 28 | artist: "Blue Wednesday, Shopan", 29 | coverUrl: 30 | "https://chillhop.com/wp-content/uploads/2020/12/33a2a875828118a3ff260638a88362936104879a-1024x1024.jpg", 31 | thumbUrl: 32 | "https://chillhop.com/wp-content/uploads/2020/12/33a2a875828118a3ff260638a88362936104879a-150x150.jpg", 33 | audio: "https://mp3.chillhop.com/serve.php/?mp3=11227", 34 | palette: "purple", 35 | id: uuidv4(), 36 | }, 37 | { 38 | title: "Airplane Mode", 39 | artist: "Axian, falcxne, Makzo", 40 | coverUrl: 41 | "https://chillhop.com/wp-content/uploads/2021/06/23b2ff959731b56ea8545828b462311e8b1a2bcc-1024x1024.jpg", 42 | thumbUrl: 43 | "https://chillhop.com/wp-content/uploads/2021/06/23b2ff959731b56ea8545828b462311e8b1a2bcc-150x150.jpg", 44 | audio: "https://mp3.chillhop.com/serve.php/?mp3=20121", 45 | palette: "green", 46 | id: uuidv4(), 47 | }, 48 | 49 | { 50 | title: "Antematter", 51 | artist: "Toonorth", 52 | coverUrl: 53 | "https://chillhop.com/wp-content/uploads/2021/05/732128e1da8fd5f6292ffc1926a2ea840a54f4d0-1024x1024.jpg", 54 | thumbUrl: 55 | "https://chillhop.com/wp-content/uploads/2021/05/732128e1da8fd5f6292ffc1926a2ea840a54f4d0-150x150.jpg", 56 | audio: "https://mp3.chillhop.com/serve.php/?mp3=17938", 57 | palette: "purple", 58 | id: uuidv4(), 59 | }, 60 | { 61 | title: "Almost Home", 62 | artist: "Chillhop Music", 63 | coverUrl: 64 | "https://chillhop.com/wp-content/uploads/2021/07/875b9624506ae8d05750b9e4ab4579abb1fe3e16-1024x1024.jpg", 65 | thumbUrl: 66 | "https://chillhop.com/wp-content/uploads/2021/07/875b9624506ae8d05750b9e4ab4579abb1fe3e16-150x150.jpg", 67 | audio: "https://mp3.chillhop.com/serve.php/?mp3=21781", 68 | palette: "green", 69 | id: uuidv4(), 70 | }, 71 | { 72 | title: "Kinship", 73 | artist: "Sleepy Fish, mommy", 74 | coverUrl: 75 | "https://chillhop.com/wp-content/uploads/2021/05/1245c0271290a3196328c0cf4aaa910cd873dfe7-1024x1024.jpg", 76 | thumbUrl: 77 | "https://chillhop.com/wp-content/uploads/2021/05/1245c0271290a3196328c0cf4aaa910cd873dfe7-150x150.jpg", 78 | audio: "https://mp3.chillhop.com/serve.php/?mp3=19060", 79 | palette: "blue", 80 | id: uuidv4(), 81 | }, 82 | { 83 | title: "Vintage", 84 | artist: "Evil Needle", 85 | coverUrl: 86 | "https://chillhop.com/wp-content/uploads/2021/04/cb0cc6270d7f2e1bb13e44e8832bd5c9b2a61080-1024x1024.jpg", 87 | thumbUrl: 88 | "https://chillhop.com/wp-content/uploads/2021/04/cb0cc6270d7f2e1bb13e44e8832bd5c9b2a61080-150x150.jpg", 89 | audio: "https://mp3.chillhop.com/serve.php/?mp3=17088", 90 | palette: "yellow", 91 | id: uuidv4(), 92 | }, 93 | { 94 | title: "Naked Sunday", 95 | artist: "CYGN", 96 | coverUrl: 97 | "https://chillhop.com/wp-content/uploads/2021/02/d12927eedcc2f5afba2ab049a4a1ea46c2266ae3-1024x1024.jpg", 98 | thumbUrl: 99 | "https://chillhop.com/wp-content/uploads/2021/02/d12927eedcc2f5afba2ab049a4a1ea46c2266ae3-150x150.jpg", 100 | audio: "https://mp3.chillhop.com/serve.php/?mp3=14998", 101 | palette: "magenta", 102 | id: uuidv4(), 103 | }, 104 | 105 | { 106 | title: "Caffeine", 107 | artist: "Felty", 108 | coverUrl: 109 | "https://chillhop.com/wp-content/uploads/2020/07/858b533ba20ff95bf5b401089b195d1a8cb43870-1024x1024.jpg", 110 | thumbUrl: 111 | "https://chillhop.com/wp-content/uploads/2020/07/858b533ba20ff95bf5b401089b195d1a8cb43870-150x150.jpg", 112 | audio: "https://mp3.chillhop.com/serve.php/?mp3=9334", 113 | palette: "blue", 114 | id: uuidv4(), 115 | }, 116 | { 117 | title: "Dojo", 118 | artist: "SwuM", 119 | coverUrl: 120 | "https://chillhop.com/wp-content/uploads/2020/04/35317644d6db24c3ca144619d03f2805fa702472-1024x1024.jpg", 121 | thumbUrl: 122 | "https://chillhop.com/wp-content/uploads/2020/04/35317644d6db24c3ca144619d03f2805fa702472-150x150.jpg", 123 | audio: "https://mp3.chillhop.com/serve.php/?mp3=8002", 124 | palette: "teal", 125 | id: uuidv4(), 126 | }, 127 | { 128 | title: "Mozambique", 129 | artist: "Comodo", 130 | coverUrl: 131 | "https://chillhop.com/wp-content/uploads/2020/07/4b06cedf68f3f842d3a0fc13ae62564dec6056c8-1024x1024.jpg", 132 | thumbUrl: 133 | "https://chillhop.com/wp-content/uploads/2020/07/4b06cedf68f3f842d3a0fc13ae62564dec6056c8-150x150.jpg", 134 | audio: "https://mp3.chillhop.com/serve.php/?mp3=8985", 135 | palette: "purple", 136 | id: uuidv4(), 137 | }, 138 | { 139 | title: "Rockaway 5pm", 140 | artist: "auv", 141 | coverUrl: 142 | "https://chillhop.com/wp-content/uploads/2020/07/8ead77b24ce86e871c31691dec6a5983b9533db1-1024x1024.jpg", 143 | thumbUrl: 144 | "https://chillhop.com/wp-content/uploads/2020/07/8ead77b24ce86e871c31691dec6a5983b9533db1-150x150.jpg", 145 | audio: "https://mp3.chillhop.com/serve.php/?mp3=9157", 146 | palette: "yellow", 147 | id: uuidv4(), 148 | }, 149 | { 150 | title: "Magenta Forever", 151 | artist: "Aviino", 152 | coverUrl: 153 | "https://chillhop.com/wp-content/uploads/2020/10/23fdd99adc3e16abcb67b004ea3e748ebf433a49-1024x1024.jpg", 154 | thumbUrl: 155 | "https://chillhop.com/wp-content/uploads/2020/10/23fdd99adc3e16abcb67b004ea3e748ebf433a49-150x150.jpg", 156 | audio: "https://mp3.chillhop.com/serve.php/?mp3=10458", 157 | palette: "pink", 158 | id: uuidv4(), 159 | }, 160 | { 161 | title: "Build", 162 | artist: "Yasper, Louk", 163 | coverUrl: 164 | "https://chillhop.com/wp-content/uploads/2020/07/f5170130ca62e18fb3928feb3d851f3f07f77e18-1024x1024.jpg", 165 | thumbUrl: 166 | "https://chillhop.com/wp-content/uploads/2020/07/f5170130ca62e18fb3928feb3d851f3f07f77e18-150x150.jpg", 167 | audio: "https://mp3.chillhop.com/serve.php/?mp3=7873", 168 | palette: "orange", 169 | id: uuidv4(), 170 | }, 171 | { 172 | title: "Whale Call", 173 | artist: "Saib", 174 | coverUrl: 175 | "https://chillhop.com/wp-content/uploads/2020/07/385d44fc6335bf676b30be524bcdfd7d640716a4-1024x1024.jpg", 176 | thumbUrl: 177 | "https://chillhop.com/wp-content/uploads/2020/07/385d44fc6335bf676b30be524bcdfd7d640716a4-150x150.jpg", 178 | audio: "https://mp3.chillhop.com/serve.php/?mp3=8099", 179 | palette: "cyan", 180 | id: uuidv4(), 181 | }, 182 | ]; 183 | 184 | export default songData; 185 | --------------------------------------------------------------------------------