برمجه صوت صوره وقائمه

 HTML



<div id="root"></div>

<a target="_blank" title="instagram/web__addict" href="https://www.instagram.com/web__addict/"><i class="fab fa-instagram"></i></a>


CSS(SCSS)


$border-radius: 20px;


$primary: #709fdc;

$base: #071739;

$shadow-color:  #274684;

$lighter-shadow: rgba($shadow-color, .7);

$white: #fff;

$gray: #8c8c8c;

$lighter-gray: rgba($gray, .1);

$time-line-width: 240px;

$transition: .3s all ease;


body{

  font-family: 'Rubik', sans-serif;

  color: $base;

  display: flex;

  justify-content: center;

  align-items: center;

  flex-direction: column;

  background: #000;

  h1{

    font-size: 36px;

    margin-bottom: 0;

  }

  .card{

    display: flex;

    flex-direction: column;

    justify-content: center;

    align-items: center;

    max-width: 371px;

    padding: 0 5px;

    margin-top: 40px;

    border-radius: $border-radius;

    color: $white;

    font-weight: 100;

    box-shadow: 0px 0px 70px 0px $shadow-color;

    background: $base;

    overflow: hidden;

    .current-song{

      display: flex;

      flex-direction: column;

      align-items: center;

      width: 100%;

      padding: 20px 0px;

      border-radius: $border-radius;

      color: $base;

      background: $white;

   

      audio{

        display: none;

      }

      .img-wrap{

        position: relative;

        margin: 0 auto;

        width: 270px;

        height: 200px;

        overflow: hidden;

        border-radius: 20px;

        box-shadow: 0px 10px 40px 0px $lighter-shadow;

        img {

          width: auto;

          height: 100%;

        }

      }

      .song-name{

        margin-top: 30px;

        font-size: 22px;

      }

      .song-autor{

        color: $primary;

      }

      .time{

        display: flex;

        justify-content: space-between;

        margin-top: 10px;

        width: $time-line-width;

      }

      #timeline{

        position: relative;

        margin: 0 auto;

        width: $time-line-width;

        height: 5px;

        background: $primary;

        border-radius: 5px;

        cursor: pointer;

        &:hover{

          .hover-playhead{

             opacity: 1;

            &::before{

              opacity: 1;

            }

            &::after{

              opacity: 1;

            }

          }

        }

        #playhead{

          position: relative;

          z-index: 2;

          width: 0;

          height: 5px;

          border-radius: 5px;

          background: $base;

        }

        .hover-playhead{

          position: absolute;

          z-index: 1;

          top: 0;

          width: 0;

          height: 5px;

          opacity: 0;

          border-radius: 5px;

          background: $shadow-color;

          transition: opacity .3s;

          &::before{

            opacity: 0;

            content: attr(data-content);

            display: block;

            position: absolute;

            top: -30px;

            right: -23px;

            width: 40px;

            padding: 3px;

            text-align: center;

            color: white;

            background: $shadow-color;

            border-radius: calc( #{$border-radius} - 12px);

          }

          &::after{

            opacity: 0;

            content:'';

            display: block;

            position: absolute;

            top: -8px;

            right: -8px;

            border-top: 8px solid $shadow-color;

            border-left:8px solid transparent;

            border-right:8px solid transparent;

          }

        }

      }

      .controls{

        margin-top: 10px;

        button{

          color: $base;

          border-radius: 50%;

          margin: 15px;

          font-size: 18px;

          text-align: center;

          transition: 0.2s;

          cursor: pointer;

          border: none;

          background: 0;

          &:focus{

            outline: none;

          }

          &.play{

            width: 50px;

            height: 50px;

            border: 1px solid #e2e2e2;

            &:hover{

              left: 0;

              box-shadow: 0px 0px 15px 0px  $lighter-shadow;

            }

            .fa-play{

              transform: translateX(2px);

            }

          }

          &.prev-next{

            width: 35px;

            height: 35px;

            &:hover{

              transform: scale(1.2);

            }

          }

        }

      }

    }

    .play-list{

      display: flex;

      flex-direction: column;

      padding: 10px;

      height: 180px;

      overflow-y: scroll;

      .track{

        display: flex;

        align-items: center;

        margin-bottom: 10px;

        border-radius: calc( #{$border-radius} - 10px);

        border: 1px solid transparent;

        transition: 0.3s;

        cursor: pointer;

        &:hover{

          background: $shadow-color;

          border-color: $shadow-color;

          position: relative;

        }

        &.current-audio{

          background: $shadow-color;

          box-shadow: 0px 0px 15px 0px $shadow-color;

        }

        &.play-now{

          background: $shadow-color;

          box-shadow: 0px 0px 15px 0px  $shadow-color;

          position: relative;

        &:after{

          content: '';

          display: block;

          position: absolute;

          left:17px;

          width: 57px;

          height: 57px;

          border-radius: calc( #{$border-radius} - 10px);

          font-size: 16px;

          animation: play 2s linear infinite;

          background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='iso-8859-1'%3F%3E%3C!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3Csvg version='1.1' id='Capa_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 56 56' style='enable-background:new 0 0 56 56;' xml:space='preserve'%3E%3Cpath style='fill:%23071739;' d='M47.799,8.201c-10.935-10.935-28.663-10.935-39.598,0c-10.935,10.935-10.935,28.663,0,39.598 c10.935,10.935,28.663,10.935,39.598,0C58.734,36.864,58.734,19.136,47.799,8.201z M32.95,32.95c-2.734,2.734-7.166,2.734-9.899,0 c-2.734-2.734-2.734-7.166,0-9.899s7.166-2.734,9.899,0S35.683,30.216,32.95,32.95z'/%3E%3Cpath style='fill:%23E7ECED;' d='M35.778,20.222c-4.296-4.296-11.261-4.296-15.556,0c-4.296,4.296-4.296,11.261,0,15.556 c4.296,4.296,11.261,4.296,15.556,0C40.074,31.482,40.074,24.518,35.778,20.222z M30.121,30.121c-1.172,1.172-3.071,1.172-4.243,0 s-1.172-3.071,0-4.243s3.071-1.172,4.243,0S31.293,28.95,30.121,30.121z'/%3E%3Cg%3E%3Cpath style='fill:%23709fdc;' d='M35.778,35.778c-0.76,0.76-1.607,1.378-2.504,1.87l8.157,14.92c2.284-1.25,4.434-2.835,6.368-4.769 c1.934-1.934,3.519-4.084,4.769-6.368l-14.92-8.157C37.157,34.172,36.538,35.018,35.778,35.778z'/%3E%3Cpath style='fill:%23709fdc;' d='M20.222,20.222c0.76-0.76,1.607-1.378,2.504-1.87l-8.157-14.92c-2.284,1.25-4.434,2.835-6.368,4.769 s-3.519,4.084-4.769,6.368l14.92,8.157C18.843,21.828,19.462,20.982,20.222,20.222z'/%3E%3C/g%3E%3C/svg%3E");

        }

        .track-img{

          filter: opacity(70%);

        }

      }

    .track-img{

      width: 90px;

      border-radius: calc( #{$border-radius} - 10px);

    }

    

        .track-discr{

          margin-left: 15px;

          display: flex;

          flex-direction: column;

          min-width: 190px;

          .track-name{

            font-size: 17px;

            margin-top: 8px;

          }

          .track-author{

            margin-top: 8px;

            font-weight: 300;

            color: $primary;

          }

        }


        .track-duration{

          min-width: 40px;

          margin-left: 10px;

          margin-right: 10px;

          font-weight: 500;

        }

      }

    }

  }

}







.fa-instagram{

  position: absolute;

  color: $base;

  top: 3%;

  right: 2%;

  font-size: 38px;

}

.fa-instagram:hover{

  font-size: 42px;

  color: $white;

  transition: all .1s linear;

  cursor: pointer;

}




.play-list::-webkit-scrollbar {

    width: 5px;

}


.play-list::-webkit-scrollbar-thumb {

  background: $white; 

  border-radius: 5px;

}


.play-list::-webkit-scrollbar-track {

  background: $base; 

}


.now-playing{

  

}


@keyframes play {

  0%{

    transform: rotate(0deg);

  }

  100% {

    transform: rotate(360deg);

  }

}


Javascript(Babel)

class CardProfile extends React.Component {

  state = {

    index: 3,

    currentTime: '0:00',

    musicList: [{name:'Nice piano and ukulele', author: 'Royalty', img: 'https://www.bensound.com/bensound-img/buddy.jpg', audio:'https://www.bensound.com/bensound-music/bensound-buddy.mp3', duration: '2:02'}, 

      {name:'Gentle acoustic', author: 'Acoustic', img: 'https://www.bensound.com/bensound-img/sunny.jpg', audio:'https://www.bensound.com//bensound-music/bensound-sunny.mp3', duration: '2:20'},

      {name:'Corporate motivational', author: 'Corporate', img: 'https://www.bensound.com/bensound-img/energy.jpg', audio:'https://www.bensound.com/bensound-music/bensound-energy.mp3', duration: '2:59'},

      {name:'Slow cinematic', author: 'Royalty', img: 'https://www.bensound.com/bensound-img/slowmotion.jpg', audio:'https://www.bensound.com/bensound-music/bensound-slowmotion.mp3', duration: '3:26'}],

    pause: false,

  };



 componentDidMount() {

   this.playerRef.addEventListener("timeupdate", this.timeUpdate, false);

   this.playerRef.addEventListener("ended", this.nextSong, false);

   this.timelineRef.addEventListener("click", this.changeCurrentTime, false);

   this.timelineRef.addEventListener("mousemove", this.hoverTimeLine, false);

   this.timelineRef.addEventListener("mouseout", this.resetTimeLine, false);

 }


  componentWillUnmount() {

    this.playerRef.removeEventListener("timeupdate", this.timeUpdate);

    this.playerRef.removeEventListener("ended", this.nextSong);

    this.timelineRef.removeEventListener("click", this.changeCurrentTime);

    this.timelineRef.removeEventListener("mousemove", this.hoverTimeLine);

    this.timelineRef.removeEventListener("mouseout", this.resetTimeLine);

  }


changeCurrentTime = (e) => {

  const duration = this.playerRef.duration;

  

  const playheadWidth = this.timelineRef.offsetWidth;

  const offsetWidht = this.timelineRef.offsetLeft;

  const userClickWidht = e.clientX - offsetWidht;

 

  const userClickWidhtInPercent = (userClickWidht*100)/playheadWidth;


  this.playheadRef.style.width = userClickWidhtInPercent + "%";

  this.playerRef.currentTime = (duration * userClickWidhtInPercent)/100;

}


hoverTimeLine = (e) => {

  const duration = this.playerRef.duration;

  

  const playheadWidth = this.timelineRef.offsetWidth

  

  const offsetWidht = this.timelineRef.offsetLeft;

  const userClickWidht = e.clientX - offsetWidht;

  const userClickWidhtInPercent = (userClickWidht*100)/playheadWidth;


  if(userClickWidhtInPercent <= 100){

    this.hoverPlayheadRef.style.width = userClickWidhtInPercent + "%";

  }

  

  const time = (duration * userClickWidhtInPercent)/100;

  

  if( (time >=0) && (time <= duration)){

    this.hoverPlayheadRef.dataset.content = this.formatTime(time);

  }

}


resetTimeLine = () => {

  this.hoverPlayheadRef.style.width = 0;

}


timeUpdate = () => {

  const duration = this.playerRef.duration;

  const timelineWidth = this.timelineRef.offsetWidth - this.playheadRef.offsetWidth;

  const playPercent = 100 * (this.playerRef.currentTime / duration);

this.playheadRef.style.width = playPercent + "%";

  const currentTime = this.formatTime(parseInt(this.playerRef.currentTime));  

  this.setState({ 

    currentTime 

  });

}


formatTime = (currentTime) =>{

  const minutes = Math.floor(currentTime / 60);

  let seconds = Math.floor(currentTime % 60);


  seconds = (seconds >= 10) ? seconds : "0" + seconds % 60;

  

  const formatTime = minutes + ":" +  seconds

 

  return formatTime;

  }


  updatePlayer = () =>{

    const { musicList, index } = this.state;

    const currentSong = musicList[index];

    const audio = new Audio(currentSong.audio);

    this.playerRef.load();

  }

  

  nextSong = () => {

    const { musicList, index, pause } = this.state;

  

    this.setState({ 

      index: (index + 1) % musicList.length

    });

    this.updatePlayer();

    if(pause){

      this.playerRef.play();

    }

  };


  prevSong = () => {

    const { musicList, index, pause } = this.state;  

    

    this.setState({ 

      index: (index + musicList.length - 1) % musicList.length

    });

    this.updatePlayer();

    if(pause){

      this.playerRef.play();

    }

  };

   


  playOrPause = () =>{

    const { musicList, index, pause } = this.state;

    const currentSong = musicList[index];

    const audio = new Audio(currentSong.audio);

    if( !this.state.pause ){

      this.playerRef.play();

    }else{

      this.playerRef.pause();

    }

    this.setState({

      pause: !pause

    })

  }

  

  clickAudio = (key) =>{

    const { pause } = this.state;

    

    this.setState({

      index: key

    });

    

    this.updatePlayer();

    if(pause){

      this.playerRef.play();

    }

  }


  

  render() {

    const { musicList, index, currentTime, pause } = this.state;

    const currentSong = musicList[index];

    return (

      <div className="card">

        <div className="current-song">

          <audio ref={ref => this.playerRef = ref}>

            <source src={ currentSong.audio } type="audio/ogg"/>

              Your browser does not support the audio element.

          </audio>

          <div className="img-wrap">

            <img src={ currentSong.img }/>

           </div>

          <span className="song-name">{ currentSong.name }</span>

          <span className="song-autor">{ currentSong.author }</span>

          

          <div className="time">

            <div className="current-time">{ currentTime }</div>

            <div className="end-time">{ currentSong.duration }</div>

          </div>

          

          <div ref={ref => this.timelineRef = ref} id="timeline">

            <div ref={ref => this.playheadRef = ref} id="playhead"></div>

            <div ref={ref => this.hoverPlayheadRef = ref} class="hover-playhead" data-content="0:00"></div>

          </div>

          

          <div className="controls">

            <button onClick={this.prevSong} className="prev prev-next current-btn"><i className="fas fa-backward"></i></button>

            

            <button onClick={this.playOrPause} className="play current-btn">

              {

                (!pause) ? <i className="fas fa-play"></i>

                :<i class="fas fa-pause"></i>

              }

            </button>

            <button onClick={this.nextSong} className="next prev-next current-btn"><i className="fas fa-forward"></i></button>

          </div>

          

        </div>

        <div className="play-list" >

          {musicList.map( (music, key=0) =>

                         <div key={key} 

                           onClick={()=>this.clickAudio(key)}

                           className={"track " + 

                             (index === key && !pause ?'current-audio':'') + 

                             (index === key && pause ?'play-now':'')} >

                           

                           <img className="track-img" src={music.img}/>

                           <div className="track-discr" >

                             <span className="track-name" >{music.name}</span>

                             <span className="track-author" >{music.author}</span>

                           </div>

                           <span className="track-duration" >

                             {(index === key)

                               ?currentTime

                               :music.duration

                             }

                           </span>

                         </div>

                        )}

        </div>

      </div>

    )

  }

}


ReactDOM.render(

  <CardProfile/>,

  document.getElementById('root')

)

وسلامتكم

إرسال تعليق

0 تعليقات