JSFiddle - React, Tailwind, and code Playground

by Keith Chu

HTML

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Pull to Open - Interaction Test</title>

    <link rel="stylesheet" href="stylesheets/style2.css" />
  </head>
  <body>
    <div class="card">
      <div class="card-inner">
        <h1>Totoro</h1>
        <img src="http://f.cl.ly/items/3N131r1b1N3f40440e2Y/totoro.jpg" />
        <p>$15</p>
      </div>
      <div class="card-outer">
        <div class="card-outer-top"></div>
        <div class="card-pulltab">
          <i class="card-cut"></i>
          <a href="#">Slice to Open</a>
        </div>
        <div class="card-outer-bottom"></div>
      </div>
    </div>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="scripts/scripts2.min.js"></script>
  </body>
</html>

CSS

/* line 1, ../sass/style2.sass */
body {
  background-image: url("http://f.cl.ly/items/400m0O0c2F0n1D421U1Q/noise-7b209cf74b1a68ced00edf9fe5bba036.gif");
  color: #454545;
  font: 30px sans-serif;
  font-weight: 100;
  padding: 100px; }

/* line 8, ../sass/style2.sass */
.card {
  border-radius: 5px;
  box-shadow: inset 0 0 3px 1px rgba(0, 0, 0, 0.5), inset 0 0 3px 4px rgba(255, 255, 255, 0.2), inset 2px 2px 2px 2px rgba(255, 255, 255, 0.5), 2px 4px 4px 1px rgba(0, 0, 0, 0.05), 1px 1px 10px rgba(0, 0, 0, 0.3);
  height: 547px;
  position: relative;
  width: 547px;
  -webkit-perspective: 900; }
  /* line 16, ../sass/style2.sass */
  .card.slicing .card-cut {
    margin-top: -3px;
    width: 100%; }
  /* line 19, ../sass/style2.sass */
  .card.slicing .card-pulltab {
    border-color: transparent;
    -webkit-animation: falloff 3s ease;
    -webkit-animation-fill-mode: forwards;
    z-index: 4; }
    /* line 24, ../sass/style2.sass */
    .card.slicing .card-pulltab:before, .card.slicing .card-pulltab:after {
      display: none; }
  /* line 26, ../sass/style2.sass */
  .card.slicing .card-outer-top {
    border-bottom: 2px solid rgba(0, 0, 0, 0.35);
    box-shadow: 0 5px 5px rgba(0, 0, 0, 0.3);
    -webkit-animation: card-open-top 1.5s ease 3s;
    -webkit-animation-fill-mode: forwards; }
  /* line 31, ../sass/style2.sass */
  .card.slicing .card-outer-bottom {
    border-top: 1px solid rgba(0, 0, 0, 0.25);
    box-shadow: 0 -5px 5px rgba(0, 0, 0, 0.3);
    -webkit-animation: card-open-bottom 1.5s ease 3s;
    -webkit-animation-fill-mode: forwards;
    -webkit-transition: falloff-outer-bottom 3s ease; }

/* line 37, ../sass/style2.sass */
.card-inner {
  background: url("http://f.cl.ly/items/3i30303K260v3Q332a2T/50-50-5-monochrome.png"), -webkit-linear-gradient(-90deg, white, rgba(255, 255, 255, 0.5));
  border-radius: 5px;
  box-shadow: inset 0 0 3px 1px rgba(0, 0, 0, 0.5), inset 0 0 3px 4px rgba(255, 255, 255, 0.2), inset 2px 2px 2px 2px rgba(255, 255, 255,...

JavaScript

var touchSupport = ('ontouchstart' in document.documentElement);
var actionStart = (touchSupport) ? 'touchstart' : 'mousedown',
    actionMove = (touchSupport) ? 'touchmove' : 'mousemove',
    actionEnd = (touchSupport) ? 'touchend touchcancel' : 'mouseup';

var touch = {},
    dx = 0, dy = 0,
    cutWidth = 0,
    cardLeftEdge = $(".card").offset().left,
    cardWidth = 540,
    swiping = false,
    swipeTolerance = 50;

$('body').on(actionStart, function(e){
  e = e.originalEvent;
  e.preventDefault();

  if (touchSupport) {
    if (e.touches.length === 1) {
      touch.x1 = e.touches[0].pageX;
      touch.y1 = e.touches[0].pageY;
    }
  } else {
    touch.x1 = e.pageX;
    touch.y1 = e.pageY;
  }

  // bind after touchstart/mousedown, so event doesn't fire haphazardly
  $(this).on(actionMove, function(e){
    e = e.originalEvent;
    e.preventDefault();

    if (touchSupport) {
      if (e.touches.length === 1) {
        dx = e.touches[0].pageX - touch.x1;
        dy = e.touches[0].pageY - touch.y1;

        if (Math.abs(dx) > 0 && Math.abs(dy) < 6 && !swiping) {
          swiping = true;
        }
      }
    } else {
      dx = e.pageX - touch.x1;
      dy = e.pageY - touch.y1;

      if (Math.abs(dx) > 0 && Math.abs(dy) < 6 && !swiping) {
        swiping = true;
      }
    }

    // a swipe motion initiated
    if (swiping)  {

      // left-to-right swipe
      if (touch.x1 < (cardLeftEdge + swipeTolerance)) {
        cutWidth = Math.min(((e.pageX - cardLeftEdge) / cardWidth) * 100, 100);
        $(".card-cut").css("width", cutWidth + "%");

        if (e.pageX > (cardWidth + cardLeftEdge - swipeTolerance)) {
          $(".card").addClass("slicing");
        }
      }

      // right-to-left swipe
      else if (touch.x1 > (cardWidth + cardLeftEdge - swipeTolerance)) {
        cutWidth = Math.min((((cardWidth + cardLeftEdge) - e.pageX) / cardWidth) * 100, 100);
        $(".card-cut").addClass("reverse").css("width", cutWidth + "%");

        if (e.pageX...