JSFiddle - React, Tailwind, and code Playground

Portal Swipe Delete

by Hugo Carneiro

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<div class="viewport-content scroll">
  <div class="content-main container-fluid">
    <div class="row">
      <div class="col-xs-12 col-md-8 col-md-offset-2">

        <div class="list list-default">
          <ul>
            <div class="helpers-wrapper">
              <p class="helper app-offline-notification"><small>Device offline</small></p>
              <p class="helper text-muted"><small>&#8592; Swipe left to delete an app</small></p>
            </div>
            <li class="linked swipe initial download">
              <div class="list-swipe-wrapper">
                <div class="list-image" style="background-image: url('http://www.brightec.co.uk/sites/default/files/AirBNBTVApp_Aux.png');"></div>
                <div class="list-desc">
                  <p class="list-title">Enterprise Apps</p>
                </div>
                <span class="icon"></span>
                <div class="swipe-action swipe-action-left">Delete</div>
              </div>
              <div class="progress animated">
                <div class="progress-bar progress-bar-flv progress-bar-striped active" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
                </div>
              </div>
            </li>
            <li class="linked swipe download">
              <div class="list-swipe-wrapper">
                <div class="list-image" style="background-image: url('http://www.underconsideration.com/brandnew/archives/medium_logo_detail_icon.png');"></div>
                <div class="list-desc">
                  <p class="list-title">Structured Networking</p>
                </div>
                <span class="icon"></span>
                <div class="swipe-action swipe-action-left">Delete</div>
              </div>
   ...

CSS

body {
  background: #FFF;
  color: #333;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-font-smoothing: antialiased;
}

.viewport-content {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.scroll {
  overflow: auto !important;
}

.content-main {
  padding-top: 70px;
}

.list.list-default ul {
  padding: 0;
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
  overflow: hidden;
}

.together.list.list-default ul {
  font-size: 1em;
  line-height: 1.25;
}

.list.list-default ul > li {
  list-style: none;
  border-bottom: 1px solid rgba(51, 51, 51, 0.2);
  padding: 15px 10px 15px 10px;
  position: relative;
  cursor: pointer;
}

.list.list-default ul > li.linked {
  padding-right: 44px;
}

.list.list-default ul > li .list-image {
  width: 50px;
  height: 50px;
  position: absolute;
  left: 10px;
  top: 50%;
  margin-top: -25px;
  border-radius: 17%;
  background-position: center center;
  background-size: cover;
  -webkit-box-shadow: 0px 0px 8px rgba(0,0,0,0.2);
  box-shadow: 0px 0px 8px rgba(0,0,0,0.2);
}

.list.list-default ul > li .list-title {
  font-size: 1em;
  font-weight: 600;
  margin: 0;
}

.list.list-default ul > li p {
  margin: 0;
}

.list.list-default ul > li .list-title + p {
  margin-top: .5em;
}

.list.list-default ul > li .list-title + p.text-danger {
  margin-top: 0;
  font-size: 0.8em;
}

.list.list-default ul > li .icon {
  position: absolute;
  width: 44px;
  top: 0;
  bottom: 0;
  right: 0;
  font-family: FontAwesome;
  cursor: pointer;
}

.list.list-default ul > li .icon:after {
  content: "\f105";
  display: block;
  text-align: center;
  font-size: 30px;
  line-height: 54px;
  position: absolute;
  width: 44px;
  top: 50%;
  margin-top: -27px;
  right: 0;
  color: #333;
}

.list.list-default ul > li.download .icon:after {
  content: "\f0ed";
  font-size: 20px;
  color:...

JavaScript

var request = true; // CHANGE THIS TO SEE ERROR MESSAGE EXAMPLE - BOOLEAN
var offlineDevice = false; // CHANGE THIS TO SEE THE OFFLINE EXAMPLE

// FUNCTION TO DISPLAY THE OFFLINE NOTIFICATION OR REMOVE IT
function checkOnline(offline) {
	if ( offline ) {
  	$('.list .helper.app-offline-notification').addClass('active');
		$('.list .helper.app-offline-notification').fadeIn(500);
  } else {
  	if ( $('.list .helper.app-offline-notification').hasClass('active') ) {
    	$('.list .helper.app-offline-notification').removeClass('active');
			$('.list .helper.app-offline-notification').fadeOut(500);
    }
  }
}

function downloadApp(fakeRequest) {
	return request ? Promise.resolve() : Promise.reject()
}

$('li.download').on('click', function(e) {
  var _this = $(this);
  
  checkOnline(offlineDevice);
  
  // IF OFFLINE SHOW MESSAGE THAT DEVICE IS OFFLINE ON THE APP THE USER CLICKS - THEN REMOVES IT
  if (offlineDevice) {
  	_this.find('.list-desc').append($('<p class="text-danger">Connect to the internet to download the app.</p>').hide().fadeIn(500));
    setTimeout(function() {
      _this.find('.text-danger').fadeOut(500).then(function() {
      	_this.find('.text-danger').remove();
      });
    }, 2000);
    return;
  }
  
	if ( !$(e.target).is('.swipe-action') ){
    if ( _this.hasClass('download') ) {
      downloadApp(request).then(function onSuccess() {
      	var stopped = false;
        _this.find('.progress').addClass('show fadeIn');
        _this.removeClass('download').addClass('cancel');
        _this.find('.progress-bar').animate({
          width: "100%"
        }, {
          duration: 5000,
          easing: "linear",
          progress: function() {
          	if ( _this.hasClass('download') ) {
            	stopped = true;
              return;
            }
          },
          complete: function() {
          	if ( !stopped ) {
              _this.find('.progress').removeClass('show fadeIn');
             ...