Vue.js Instagram Clone Web App in Browser Using CSSGram and Javascript Full Project For Beginners

Vue.js Instagram Clone Web App in Browser Using CSSGram and Javascript Full Project For Beginners
  • Post author:
  • Post category:Vue
  • Post comments:0 Comments

 

Welcome folks today in this blog post we will be building a instagram clone web app in browser using cssgram library and javascript. All the full source code of the application is shown below.

 

 

Get Started

 

 

In order to get started you need to create an index.html file and copy paste the below code

 

index.html

 

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.min.css"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.9/css/all.css"/>
<link rel="stylesheet" href="https://cssgram-cssgram.netdna-ssl.com/cssgram.min.css"/>

<div id="app">
  <div class="app__phone">
    <div class="phone-header">
      <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/Instagram_logo.png" />
      <p class="cancel-cta" v-if="step === 2 || step === 3" @click="goToHome">Cancel</p>
      <p class="next-cta" v-if="step === 2" @click="step++">Next</p>
      <p class="next-cta" v-if="step === 3" @click="sharePost">Share</p>
    </div>
    <transition name="fade">
      <div class="feed" v-if="step === 1" v-dragscroll.y="true">
        <instagram-post v-for="post in posts"
                        :post="post"
                        :key="posts.indexOf(post)">
        </instagram-post>
      </div>
    </transition>
    <div v-if="step === 2">
      <div class="selected-image"
           :class="filterType"
           :style="{ backgroundImage: 'url(' + image + ')' }"></div>
      <div class="filter-container" v-dragscroll.x="true">
        <filter-type v-for="filter in filters"
                     :filter="filter"
                     :image="image"
                     :key="filter.name">
        </filter-type>
      </div>
    </div>
    <div v-if="step === 3">
      <div class="selected-image"
           :class="filterType"
           :style="{ backgroundImage: 'url(' + image + ')' }"></div>
      <div class="caption-container">
        <textarea class="caption-input"
                  placeholder="Write a caption..."
                  type="text"
                  v-model="caption">
        </textarea>
      </div>
    </div>
    <div class="phone-footer">
      <div class="home-cta" @click="goToHome">
        <i class="fas fa-home fa-lg"></i>
      </div>
      <div class="upload-cta">
        <input type="file"
               name="file"
               id="file"
               class="inputfile"
               @change="fileUpload"
               v-model="fileInput"
               :disabled="step !== 1"/>
        <label for="file">
          <i class="far fa-plus-square fa-lg"></i>
        </label>
        <p v-if="step === 1">
          Click <a @click="uploadRandomImage">here for a random image!</a> or upload your own! <i class="fas fa-chevron-right"></i>
        </p>
      </div>
    </div>
  </div>
  <div class="details">
    <a class="button is-primary is-small is-info" v-if="!showDetails" @click="showDetails = !showDetails">Details</a>
    <ul v-else>
      <li>Navigate the feed by <span>dragging (or scrolling)</span></li>
      <li>Upload an image with <span><i class="far fa-plus-square fa-lg"></i></span></li>
      <li>Like a post with <span><i class="far fa-heart fa-lg"></i></span> or <span>double clicking an image</span></li>
    </ul>
  </div>
  <a href="https://twitter.com/djirdehh" target="_blank" class="twitter-section">
    <i class="fab fa-twitter" aria-hidden="true"></i>
  <a>
</div>

<!--  Prefetch random images -->
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/tropical_beach.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/downtown.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/cat.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/sushi.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/pug_personal.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/pineapple.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/tropical_ocean.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/velvet_monkey.jpg" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/codepen_logo.png" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/me2.png" />
<link rel="prefetch" href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/me_3.jpg" />

    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
    
    <script src="https://unpkg.com/vue-dragscroll@1.3.1/dist/vue-dragscroll.min.js"></script>

 

READ  Vue.js Draggable Floating Navigation Menubar With Submenu Items List Using vue-float-menu Library in Typescript Full Project For Beginners

 

Now make a style.css file and copy paste the following code

 

style.css

 

@import url('https://fonts.googleapis.com/css?family=Roboto:400,700');
 html, body, #app {
     height: 100%;
     margin: 0;
     overflow: hidden;
     background: #e6ecf1;
     font-family: 'Roboto', sans-serif;
}
 #app {
     display: flex;
     align-items: center;
     justify-content: center;
}
 .app__phone {
     background-color: white;
     height: 620px;
     width: 375px;
     overflow: hidden;
}
 .phone-header {
     height: 50px;
     width: 375px;
     position: sticky;
     position: -webkit-sticky;
     top: 0;
     background: #fafafa;
     border-bottom: 1px solid #eee;
     z-index: 99;
}
 .phone-header img {
     max-width: 100px;
     display: block;
     margin: 0 auto;
     padding-top: 10px;
}
 .phone-header .cancel-cta, .phone-header .next-cta {
     position: absolute;
     top: 12px;
     color: #209cee;
     font-weight: bold;
     cursor: pointer;
}
 .phone-header .cancel-cta {
     left: 10px;
}
 .phone-header .next-cta {
     right: 10px;
}
 .feed {
     height: 100%;
     overflow-y: scroll;
     overflow-x: hidden;
     margin-right: -15px;
}
 .instagram-post {
     padding-top: 50px;
}
 .instagram-post ~ .instagram-post {
     padding-top: 0;
}
 .instagram-post {
     padding: 5px 0;
}
 .instagram-post .header {
     height: 30px;
     border-bottom: 1px solid #fff;
     margin: 7.5px 10px;
}
 .instagram-post .header .image {
     display: inline-block;
}
 .instagram-post .header img {
     border-radius: 99px;
}
 .instagram-post .header .username {
     padding-left: 5px;
     font-size: 0.9rem;
     font-weight: bold;
}
 .instagram-post .image-container {
     height: 330px;
     background-repeat: no-repeat;
     background-position: center center;
     background-size: cover;
}
 .instagram-post .content {
     margin: 7.5px 10px;
}
 .instagram-post .far.fa-heart, .instagram-post .fas.fa-heart {
     cursor: pointer;
}
 .instagram-post .fas.fa-heart {
     color: #f06595;
}
 .instagram-post .likes {
     margin: 5px 0;
     margin-bottom: 5px !important;
     font-size: 0.85rem;
     font-weight: bold;
}
 .instagram-post .caption {
     font-size: 0.85rem;
}
 .instagram-post .caption span {
     font-weight: bold;
}
 .instagram-post:last-child {
     margin-bottom: 80px;
}
 .selected-image {
     background-repeat: no-repeat;
     background-size: cover;
     background-position: center center;
     height: 330px;
}
 .filter-container {
     height: 210px;
     padding: 30px 10px;
     white-space: nowrap;
     overflow-x: hidden;
}
 .filter-type {
     width: 100px;
     display: inline-block;
     margin: 0 3px;
}
 .filter-type p {
     font-size: 11px;
     text-align: center;
     text-transform: capitalize;
     padding-bottom: 5px;
}
 .filter-type .img {
     cursor: pointer;
     width: 100px;
     height: 100px;
     background-size: cover;
     background-position: center center;
}
 .filter-type:last-child {
     margin-right: 20px;
}
 .caption-container {
     height: 210px;
     display: flex;
     align-items: center;
     justify-content: center;
}
 .caption-container textarea {
     border: 0;
     font-size: 1rem;
     width: 100%;
     padding: 10px;
     border-bottom: 1px solid #eee;
}
 .caption-container textarea:focus {
     outline: 0;
}
 .phone-footer {
     height: 35px;
     width: 375px;
     position: sticky;
     position: -webkit-sticky;
     bottom: 0;
     background: #fafafa;
     border-top: 1px solid #eee;
     z-index: 99;
}
 .phone-footer .home-cta {
     position: absolute;
     left: 10px;
     top: 6px;
     cursor: pointer;
}
 .phone-footer .upload-cta {
     position: absolute;
     right: 10px;
     top: 6px;
}
 .phone-footer .upload-cta p {
     font-size: 0.63rem;
     position: absolute;
     left: -25px;
     top: 5px;
}
 .phone-footer input[name="file"] {
     visibility: hidden;
}
 .phone-footer label {
     cursor: pointer;
     z-index: 99;
}
 .details {
     position: absolute;
     left: 10px;
     bottom: 10px;
}
 .details li {
     font-size: 0.8rem;
}
 .details li span {
     font-weight: bold;
}
 .twitter-section {
     position: absolute;
     right: 10px;
     bottom: 10px;
}
 .twitter-section .fa-twitter {
     color: #209cee;
     font-size: 2rem;
}
 .twitter-section .fa-twitter:hover {
     color: #1496ed;
}
 .fade-leave-active {
     transition: opacity 0.5s;
}
 .fade-leave-to {
     opacity: 0;
}
 @media (max-width: 520px) {
     #app {
         height: 100% !important;
         padding-top: 0 !important;
    }
     .app__phone, .app__phone__scroll__cover {
         height: 100%;
         width: 100%;
    }
     .phone-header, .phone-footer {
         width: 100%;
    }
}
 @media (max-width: 520px) {
     .details {
         display: none;
    }
}
 @media (max-width: 1216px) and (max-height: 768px) {
     #app {
         height: initial;
         padding-top: 5px;
    }
}

 

READ  Vue.js Native HTML5 RGB Hexadecimal Color Picker Using vue-color-picker-board Library in Javascript Full Project For Beginners

 

Now make a script.js file and copy paste the following code

 

script.js

 

const EventBus = new Vue();

const posts = [
   {
    username: 'socleansofreshh',
    userImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/me_3.jpg',
    postImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/tropical_beach.jpg',
    likes: 36,
    upVoted: false,
    caption: "When you're too ready for summer '18 ☀️",
    filter: 'perpetua'
   },
   {
    username: 'djirdehh',
    userImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/me2.png',
    postImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/downtown.jpg',
    likes: 20,
    upVoted: false,
    caption: 'Views from the six...',
    filter: 'clarendon'
   },
   {
    username: 'puppers',
    userImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/pug_personal.jpg',
    postImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/puppers.jpg',
    likes: 49,
    upVoted: false,
    caption: 'Current mood 🐶',
    filter: 'lofi'
  }
]

const filters = [
  { name: 'normal' }, { name: 'clarendon' }, { name: 'gingham' }, { name: 'moon' }, { name: 'lark' }, { name: 'reyes' }, { name: 'juno' }, { name: 'slumber' }, { name: 'aden' }, { name: 'perpetua' }, { name: 'mayfair' }, { name: 'rise' }, { name: 'hudson' }, { name: 'valencia' }, { name: 'xpro2' }, { name: 'willow' }, { name: 'lofi' }, { name: 'inkwell' }, { name: 'nashville' }
]

Vue.component('instagram-post', {
  template: 
  `
    <div class="instagram-post">
      <div class="header level">
          <div class="level-left">
            <figure class="image is-32x32">
              <img :src="post.userImage" />
            </figure>
            <span class="username">{{post.username}}</span>
          </div>
      </div>
      <div class="image-container"
           :class="post.filter"
           :style="{ backgroundImage: 'url(' + post.postImage + ')' }"
           @dblclick="like">
      </div>
      <div class="content">
        <div class="heart">
          <i class="far fa-heart fa-lg"
            :class="{'fas': !this.post.upVoted,  'fas': this.post.upVoted}"
            @click="like">
          </i>
        </div>
        <p class="likes">{{post.likes}} likes</p>
        <p class="caption"><span>{{post.username}}</span> {{post.caption}}</p>
      </div>
    </div>
  `,
  props: ['post'],
  methods: {
    like() {
      this.post.upVoted ? this.post.likes-- : this.post.likes++;
      this.post.upVoted = !this.post.upVoted;
    }
  }
});

Vue.component('filter-type', {
  template:
  `
   <div class="filter-type">
     <p>{{filter.name}}</p>
    <div class="img"
         :class="filter.name"
         :style="{ backgroundImage: 'url(' + image + ')' }"
         @click="selectFilter">
    </div> 
   </div>
  `,
  props: ['filter', 'image'],
  methods: {
    selectFilter() {
      EventBus.$emit('selectFilter', {filter: this.filter.name});
    }
  }
});

new Vue({
  el: "#app",
  data: {
    posts,
    image: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/downtown.jpg',
    caption: '',
    filterType: 'normal',
    step: 1,
    showDetails: false,
    fileInput: ''
  },
  created () {
    EventBus.$on('selectFilter', (evt) => {
      this.filterType = evt.filter;
    })
  },
  methods: {
    fileUpload(e) {
      const files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;
      this.image = files[0];
      this.createImage();
    },
    createImage() {
      const image = new Image();
      const reader = new FileReader();

      reader.onload = e => {
        this.image = e.target.result;
        this.step = 2;
      };
      reader.readAsDataURL(this.image);
    },
    uploadRandomImage() {
      const randomImages = [
        'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/cat.jpg',
        'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/sushi.jpg',
        'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/velvet_monkey.jpg',
        'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/pineapple.jpg',
        'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/tropical_ocean.jpg'
      ];
      
      this.image = randomImages[Math.floor(Math.random() * randomImages.length)];
      this.step = 2;
    },
    goToHome() {
      this.image = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/downtown.jpg';
      this.caption = '';
      this.filterType = 'normal';
      this.step = 1;
    },
    sharePost() {
      const post = {
        username: 'codepen',
        userImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1211695/codepen_logo.png',
        postImage: this.image,
        likes: 0,
        caption: this.caption,
        filter: this.filterType
      }
      
      this.posts.unshift(post);
      this.goToHome();
    }
  }
});

 

READ  Vue.js Vuex 2.0 TODO CRUD List App in Browser Using Javascript Full Project For Beginners

 

And now if you open the index.html file inside the browser you will see the below screenshot

 

 

Leave a Reply