<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Josefin+Sans:300,400,700&display=swap" rel="stylesheet">
  <script src="https://kit.fontawesome.com/20d5c757b7.js" crossorigin="anonymous"></script>
</head>
<body>
<div id="root"></div>
</body>
$light: #FDFDFD;
$dark: #444444;
$shadow: #c4c4c4;
$accent: #583D91;

$anim: 0.15s;

html, body{
  font-family: 'Josefin Sans', sans-serif;
  font-size: 10px;
}

body, #root{
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #bbddee;
  width: 100%;
  height: 100%;
  margin: 0;
}
body{
  min-height: 100vh;
}

i{
  text-align: center;
  transition: $anim;
  &.fa-forward{
    padding-left: 4px;
  }
  &.fa-backward{
    padding-right: 4px;
  }
  &.fa-play{
    padding-left: 3px;
  }
}

.player{
  position: relative;
  display: flex;
  width: 32rem;
  height: 64rem;
  font-size: 1.6rem;
  overflow: hidden;
}

.btn{
  &--play{
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    margin-left: 1rem;
    border-radius: 1.2rem;
    background-color: rgba($dark, 0.2);
    border: none;
    transition: $anim;
    i{
      opacity: 0.7;
    }
    &:not(:disabled):hover{
      border-radius: 50%;
      i{
        opacity: 1;
      }
    }
    &:focus{
      outline: none;
      box-shadow: 0 0 0.5rem $shadow;
    }
  }
  &--list{
    
  }
}

.list{
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding:  0 0 1rem;
  background-color: $light;
  border-radius: 1rem;
  box-sizing: border-box;
  overflow: hidden; 
  &__wrapper{
    padding: 2rem 0 6rem;
    flex: 1;
    width: calc(100% + 1.7rem); 
    overflow-y: auto; 
    &.bg{
      .list__item{
        transform: translate3d(0, 2rem, -2rem) scale(0.9);
        opacity: 0.5;
      }
      .list__cover{
        transform: translateX(-2rem);
        opacity: 0;
      }
      .info__duration{
        opacity: 0;      
      }
    }
  }
  &__item{
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    padding: 0.6rem 3rem 0.6rem 1.5rem;
    transition: $anim*2 ease-in;
    box-sizing: border-box;
    background-color: $light;
    &:before{
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      z-index: -1;
      width: 100%;
      height: 100%;
      background-image: linear-gradient(to right, rgba($accent, 0.2), rgba($accent, 0.02));
      opacity: 0;
      transition: $anim*2 ease-out;
      transform: translateX(-100%);
    }
    &:not(:disabled):hover{
      transition-delay: 0s !important;
    }
    &:not(:disabled):hover, &.active{
      z-index: 2;      
      &:before{
        transform: translateX(0);
        opacity: 1;
      }
    }
  }
  &__cover{
    position: relative;
    z-index: 2;
    display: flex;
    width: 4rem;
    height: 4rem;
    border-radius: 1.2rem;
    overflow: hidden;
    margin: 0;
    filter: drop-shadow(0 0.3rem 0.3rem rgba($shadow, 0.2));
    transition: $anim*2;
    img{
      position: absolute;
      width: 100%;
      height: 100%;
    }    
  }
  &__title{
    position: relative;
    display: flex;
    align-items: center;
    height: 8rem;
    font-size: 2.4rem;
    padding: 0 1.5rem 0 3rem;
    color: $light;
    background-color: $accent;
    margin: 0;
    border-radius: 0 0 4rem 0;
  }
  &__action{
    position: absolute;
    z-index: 10;
    bottom: -2.5rem;
    right: 2rem;
    width: 5.4rem;
    height: 5.4rem;
    border-radius: 50%;
    background-color: $light;
    box-shadow: 0 0.5rem 1rem rgba($accent, 0.3);
    transition: $anim;
    opacity: 0;
    transform: scale(0);
    animation: scale $anim*2 forwards;
    i{
      color: $accent;
      font-size: 2rem;
    }
    &:hover{
      box-shadow: 0 0.3rem 0.6rem rgba($accent, 0.4);      
    }
  }
}

.info{
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  flex: 1;
  width: calc(100%);
  height: 100%;
  cursor: pointer;
  padding: 1rem;
  box-sizing: border-box;
  border-radius: 1.2rem;
  transition: $anim;  
  &__author, &__name{
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
  }
  &__author, &__duration{
    color: rgba($dark, 0.6);
    font-size: 1.2rem;
  }
  &__name{
    font-size: 1.4rem;
    font-weight: 700;
    margin: 0 auto 0.5rem 0;
  }
  &__status{
    position: absolute;
    bottom: -0.5rem;
    left: 1.5rem;
    display: flex;
    width: calc(100% - 3rem);
    height: 0.2rem;
    border-radius: 0.1rem;
    background-color: rgba($light, 0.5);
    span{
      height: 100%;
      background-color: rgba($light, 0.8);      
    }
  }
  &__duration{
    transition: $anim*2;
  }
}

.song{
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  background-color: $accent;
  border-radius: 2rem;
  padding-bottom: 8rem;
  box-sizing: border-box;
  transform: translateY(-58rem);
  transition: $anim*3;
  box-shadow: 0 0rem 1rem rgba(#2B0063, 0.4);
  animation: popup $anim*3 forwards;
  // animation: fullpopup $anim*2 forwards;
  &__cover-wrapper, &__info{
    width: 100%;
    height: 50%;
    flex: 1;
  }
  &__cover-wrapper{
    position: relative;
    display: flex;
    align-items: flex-end;   
    transition: $anim*2;
  }
  &__cover{
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    display: flex;
    align-items: flex-end;
    border-radius: 1rem 1rem 50% 50%;
    box-shadow: 0 0.5rem 0.5rem rgba($dark, 0.3);
    transition: $anim*2;
    transition-delay: $anim*2;
    img{      
      position: absolute;
      top: 50%;
      left: 50%;
      z-index: -1;
      min-width: 100%;
      width: 100%;
      min-height: 100%;
      transform: translate(-50%, -50%);
    }
  }
  &__info{    
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    box-sizing: border-box;
  }
  &__name{
    display: flex;
    align-items: center;
    text-transform: uppercase;
    font-weight: 700;
    font-size: 2.4rem;
    flex: 1;
    span{
      text-align: center;
      background: -webkit-linear-gradient(left, $light 50%, rgba($light, 0.4) 50%) right;
      background-size: 200%;
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      animation: fill $anim*100 forwards linear;      
    }
  }
  &__author{
    position: absolute;
    top: 2rem;
    left: 0;
    width: 100%;
    text-align: center;
    text-transform: none;
    font-size: 1.6rem;
    font-weight: 500;
    -webkit-text-fill-color: rgba($light, 0.6);
  }
  &__panel, &__actions{
    .btn--play{
      margin: 0;
      color: $light;
      background-color: transparent;
      transition: $anim*2;
      &:not(:disabled):hover{
        background-color: rgba($light, 0.3);
      }
    }
  }
  &__panel{
    display: flex;
    justify-content: center;
    width: 100%;
    .btn--play{
      height: 5rem;
      width: 5rem;
      i{
        font-size: 2.4rem;
      }
      &:not(:last-child){
        margin-right: 2rem;
      }
    }
  }
  &__actions{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 0 1rem;
    .btn--play{      
      opacity: 0;
      animation-delay: $anim*3;
      animation: horizontalShift forwards $anim*4;
      i{
        font-size: 1.8rem;
      }
      &:first-child{
        transform: translateX(-100%);
      }
      &:last-child{
        transform: translateX(100%);
      }
    }
  }
  &.simple{
    transform: translateY(-8rem);
    // transition: $anim*2;
    // opacity: 0;
    .song{
      &__cover-wrapper{
        transform: scale(0.8);
        transition: $anim/3;
        border-radius: 1.2rem;
        flex: 0;
      }
      &__cover{
        transform: scale(0.8);
        transition: $anim/5;
        border-radius: 50%;        
      }
      &__info{
        height: 10%;
        flex: none;
        flex-direction: row;
        padding: 3rem 1.5rem 1rem;
      }
      &__name{
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        cursor: pointer;
        span{ 
          text-transform: none;
          background-color: $light;
          font-size: 1.6rem;
          animation: none;
          line-height: 1.2;
        }        
      }
      &__author{
        position: static;
        text-align: left;
        font-size: 1.2rem;
        font-weight: 300;
      }
      &__panel{
        width: auto;
        .btn--play{
          margin: 0;
          height: 3.6rem;
          width: 3.6rem;
          i{
            font-size: 1.4rem;
          }
          &.prev{
            display: none;
          }
        }
      }
    }
    .backward i{
      transform: rotate(-180deg);
    }    
  }
}

.backward{
  cursor: pointer;
  position: absolute;
  top: -1rem;
  right: 1rem;
  width: 3rem;
  height: 3rem;
  border-radius: 1rem;
  z-index: 3;
  color: $accent;
  background-color: $light;
  transition: $anim;
  box-shadow: 0 0 1rem rgba($accent, 0.2);
  i{
    font-size: 1.8rem;
    transition: $anim;
  }
}

@keyframes horizontalShift{
  100%{
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes scale{
  100%{
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes fill{
  100%{
    background-position: left;
  }
}

@keyframes popup{
  0%{
    opacity: 0;
  }
  100%{
    opacity: 1;
  }
}

@keyframes fullpopup{
  100%{
    transform: translateY(-94%);
  }
}
View Compiled
const songList  = [
  {name:'Sanctified with Dynamite', author: 'PowerWolf', duration: '3:51', cover: 'https://cdnb.artstation.com/p/assets/images/images/010/532/065/large/zsofia-dankova-1.jpg?1539776234'},
  {name:'Army of the Night', author: 'PowerWolf', duration: '3:51', cover: 'https://i.pinimg.com/originals/10/37/36/1037361b721513a7168e1dae07139f55.jpg'},
  {name:'Higher Than Heaven', author: 'PowerWolf', duration: '3:51', cover: 'https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/b81633f7-ac45-4e1d-9255-46297d588240/dcf39re-204aaff0-a53f-4f9b-83d3-81239bf35778.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2I4MTYzM2Y3LWFjNDUtNGUxZC05MjU1LTQ2Mjk3ZDU4ODI0MFwvZGNmMzlyZS0yMDRhYWZmMC1hNTNmLTRmOWItODNkMy04MTIzOWJmMzU3NzgucG5nIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.fE1cp7I7GjauqJ8gKCoqz2cK1BHjeAwhivRnE7oMsVo'},
  {name:'Incense & Iron', author: 'PowerWolf', duration: '3:51', cover: 'https://i.pinimg.com/originals/2b/ca/63/2bca632180d842a6f15908154ce862bb.jpg'},
  {name:'Venom of Venus', author: 'PowerWolf', duration: '3:51', cover: 'https://steamuserimages-a.akamaihd.net/ugc/941709259346307842/830C554F58DDEF61ACD21D28FBC3FC4FEAAAE136/'},
  {name:'Sanctified with Dynamite', author: 'PowerWolf', duration: '3:51', cover: 'https://cdnb.artstation.com/p/assets/images/images/010/532/065/large/zsofia-dankova-1.jpg?1539776234'},
  {name:'Army of the Night', author: 'PowerWolf', duration: '3:51', cover: 'https://i.pinimg.com/originals/10/37/36/1037361b721513a7168e1dae07139f55.jpg'},
  {name:'Higher Than Heaven', author: 'PowerWolf', duration: '3:51', cover: 'https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/b81633f7-ac45-4e1d-9255-46297d588240/dcf39re-204aaff0-a53f-4f9b-83d3-81239bf35778.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7InBhdGgiOiJcL2ZcL2I4MTYzM2Y3LWFjNDUtNGUxZC05MjU1LTQ2Mjk3ZDU4ODI0MFwvZGNmMzlyZS0yMDRhYWZmMC1hNTNmLTRmOWItODNkMy04MTIzOWJmMzU3NzgucG5nIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmZpbGUuZG93bmxvYWQiXX0.fE1cp7I7GjauqJ8gKCoqz2cK1BHjeAwhivRnE7oMsVo'},
  {name:'Incense & Iron', author: 'PowerWolf', duration: '3:51', cover: 'https://i.pinimg.com/originals/2b/ca/63/2bca632180d842a6f15908154ce862bb.jpg'},
  {name:'Venom of Venus', author: 'PowerWolf', duration: '3:51', cover: 'https://steamuserimages-a.akamaihd.net/ugc/941709259346307842/830C554F58DDEF61ACD21D28FBC3FC4FEAAAE136/'},
]

const Btn = ({className = '', icon = 'play_arrow', children, ...props}) => (
  <button className={`btn--play ${className}`} {...props}>
    {children 
      ? children
      : <i class={`fa fa-${icon}`}/>
    }
  </button>
)


const SongList = ({list = [], stop, handle, active, open}) => (
  <div className='list'> 
    <h3 className='list__title'>
      Songs
      {(!active && active !== 0) && 
        <Btn className='list__action' icon='play' onClick={() => stop(0)}/>
      }
    </h3>
    <div className={`list__wrapper ${open ? 'bg': ''}`}>
      {list.map((el,index) => (
        <div className={`list__item ${active === index ? 'active' : ''}`} style={{transitionDelay: `${0.075 * index}s`}} onClick={() => stop(index)}>
          <span className='list__cover' style={{transitionDelay: `${0.075 * index}s`}}>
            <img src={el.cover}/>
          </span>
          <div className='info' >
            <span className='info__name'>{el.name}</span>
            <span className='info__author'>{el.author}</span>
          </div>
          <span className='info__duration' style={{transitionDelay: `${0.075 * index}s`}}>{el.duration}</span>
        </div>
      ))}
    </div>
  </div>
)

const SongPage = ({index, stop, next, prev, open, handleOpen, pause}) => {
  const data = songList[index];
  return (
  <div class={`song ${open ? '' : 'simple'}`}>
    <Btn className='backward' icon='angle-down' onClick={handleOpen}/>
      <div className='song__cover-wrapper'>
        <div class="song__cover">
          <img src={data.cover} alt="" />
        </div>
        {open && 
          <div className='song__actions'>
            <Btn className='song__btn' icon='random'/>
            <Btn className='song__btn' icon='repeat'/>
          </div>
        }
      </div>
    <div class="song__info">
      <span class="song__name" onClick={!open ? handleOpen : undefined}>
        <span>{data.name}</span>
        <span class="song__author">{data.author}</span>
      </span>
      <div class="song__panel">
        {open && <Btn className='song__btn prev' icon='backward' disabled={!prev} onClick={prev}/>}
        <Btn className='song__btn' icon={pause ? 'play' : 'pause'} onClick={() => stop(index)}/>
        <Btn className='song__btn next' icon='forward' disabled={!next} onClick={next}/>
      </div>
      {!open && <span className='info__status'><span></span></span>}
    </div>
  </div>
)
};

class App extends React.Component{
  state = {
    open: false,
    active: false,
    pause: false
  };

  handleOpen = () => { this.setState(state => ({ open: !state.open }) )};
  pause = () => {this.setState(state => ({ pause: !state.pause}) )}
  handlePlay = (active) => {
    this.setState(state => ({
      active: state.active === active ? false : active
    }))
  };
  next = () => this.handlePlay(this.state.active < songList.length - 1 ? this.state.active + 1 : 0);
  prev = () => this.handlePlay(this.state.active > 0 ? this.state.active - 1 : songList.length - 1);

  render(){
    const {active, open, pause} = this.state;
    return (
      <div className='player'>
        <SongList 
          list={songList} 
          stop={this.handlePlay} 
          open={open} 
          handle={this.handlePlay} 
          active={active}
        />
        {(active || active === 0) && 
          <SongPage
            open={open}
            index={active} 
            handleOpen={this.handleOpen} 
            pause={pause}
            stop={this.pause}
            next={this.next} 
            prev={this.prev}/>
        }
      </div>
    )
  }
};

ReactDOM.render(
  <App/>,
  document.getElementById('root'),
  )
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js