JSFiddle - React, Tailwind, and code Playground

by makilo123

HTML

<div id="wrapper">
  <upload-image help="Specific requirements for this dropzone"></upload-image>
</div>

<template id="dropzone">
  <div v-if="!image">
      <div 
        :class="['dropzone-area', dragging ? 'dropzone-over' : '']" 
        @dragover="handleDragOver()" 
        @dragenter="dragging=true" 
        @dragleave="dragging=false">

          <div class="dropzone-text">
              <span class="dropzone-title">Drop image here or click to select</span>
              <span class="dropzone-info" v-if="help">{{ help }}</span>
          </div>
          <input type="file" @change="onFileChange">
      </div>
  </div>
  <div class="dropzone-preview">
      <img :src="image" />
      <button @click="removeImage" v-if="image">Remove</button>
  </div>
</template>

SCSS

.dropzone-over {
  
  border: 1px solid red !important;
}

.dropzone-area {
    width: 80%;
    height: 200px;
    position: relative;
    border: 2px dashed #CBCBCB;
    &:hover {
        border: 2px dashed #2E94C4;
        .dropzone-title {
          color: #1975A0;
        }

    }
}

.dropzone-area input {
    position: absolute;
    cursor: pointer;
    top: 0px;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
}

.dropzone-text {
    position: absolute;
    top: 50%;
    text-align: center;
    transform: translate(0, -50%);
    width: 100%;
    span {
        display: block;
        font-family: Arial, Helvetica;
        line-height: 1.9;
    }
}

.dropzone-title {
    font-size: 13px;
    color: #787878;
    letter-spacing: 0.4px;
}
.dropzone-info {
    font-size: 13px;
    font-size: 0.8125rem;
    color: #A8A8A8;
    letter-spacing: 0.4px;
}

.dropzone-button {
    position: absolute;
    top: 10px;
    right: 10px;
    display: none;
}

.dropzone-preview {
    width: 80%;
    position: relative;
    &:hover .dropzone-button {
        display: block;
    }
    img {
      display: block;
      height: auto;
      max-width: 100%;
    }
    
}

JavaScript

Vue.component('upload-image', {
	
  template: '#dropzone',
  
  props: ['help'],

  data() {
      return {
          image: '',
          dragging: false
      }
  },

  methods: {
  		handleDragOver() {
  			console.log(this.dragging)
      },
      onFileChange(e) {
          var files = e.target.files || e.dataTransfer.files;
          if (!files.length) return;
          this.createImage(files[0]);
      },
      createImage(file) {
          var image = new Image();
          var reader = new FileReader();
          var vm = this;

          reader.onload = (e) => {
              vm.image = e.target.result;
          };
          reader.readAsDataURL(file);
      },
      removeImage: function (e) {
          this.image = '';
      }
  }
  
});

new Vue({
	el: '#wrapper'
});