├── 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 ;
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 |
7 |
8 |
9 |
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 |
7 |
8 |
9 |
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 |
7 |
8 |
9 |
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 |
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 |
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 |
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 |
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 |
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 | You need to enable JavaScript to run this app.
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 |
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 |
34 |
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 |
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 |
45 | About The Project
46 |
49 |
50 |
51 | Getting Started
52 |
56 |
57 | Contributing
58 | License
59 | Contact
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 |
--------------------------------------------------------------------------------