123

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              #cart
  %h2 Your Shopping Cart
  %ul.cart-items
  .total
    .subtotalTotal
      Subtotal
      %span $0.00
    .taxes
      Tax
      %span $0.00
    .shipping
      Shipping
      %span $0.00
    .finalTotal
      Total
      %span $0.00
    %a.checkout
      Check Out
    %p.error 
        
.wrap#wrap
  %header
    %a.logo{:href=>"#"}
      Octocat <span class="brandico-github"></span> Outfitters
    %a.cart-link{:href=>"#menu"}
      %span.cart-text.fontawesome-shopping-cart
        %span Cart
      %span.returnToShop &larr; Back        
      %span.cart-quantity.empty 0

        
  %section.shop
  
  %footer
    %p Crafted for the Pattern Rodeo (rodeo-007). Images belong to Github.

    
// Product Templates for Shop & Cart

%script#productTemplate{ type: 'text/template' }
  <div class="product">
  <h1></h1>
  <p></p>
  <div class="button">
  <div class="price"></div>
  <a class="addtocart">
  <div class="add">Add to Cart</div>
  <div class="added">Added!</div>
  </a>
  </div>
  </div>
  
%script#cartItem{ type: 'text/template' }
  <li><div class="cart-product">
  <input class="quantity" value="1">
  </div><div class="cart-description">
  <h3></h3>
  <span class="subtotal"></span>
  </div></li>
            
          
!
            
              @import compass

@import url(https://fonts.googleapis.com/css?family=Lato:400,700)

/* Iconfonts
   ============================ */

@import "http://weloveiconfonts.com/api/?family=fontawesome"
@import "http://weloveiconfonts.com/api/?family=brandico"

[class*="fontawesome-"]:before
  font-family: 'FontAwesome', sans-serif
[class*="brandico-"]:before
  font-family: 'brandico', sans-serif


/* Variables
   ============================ */

$white: #fff
$black: #111
$gray: lighten($black, 25%)

$lightblue: #9cdaf0
$blue: #7cbae6 
$darkblue: darken($blue, 25%)


/* Body
   ============================ */

body
  position: relative
  font-family: 'Lato', sans-serif
  font-weight: 300
  font-size: 1em
  color: darken($white, 20%)
  
/* Header
   ============================ */

header
  width: 100%
  border-bottom: 1px solid $blue
  background: lighten($black, 5%)

  /* Logo */  
  
  a.logo
    margin-left: 1em
    text-transform: uppercase
    text-decoration: none
    color: $blue
    line-height: 4em

    span
      margin: 0 3px 0 3px
      color: $lightblue
      
  /* Cart link */  
  
  a.cart-link
    float: right
    padding-left: 1em
    margin-right: 1em
    border-left: 1px dotted $gray 
    line-height: 4em
    text-decoration: none
    color: $white
    transition: color 150ms ease-out
    
    &:hover
      color: $blue
      
    &:active, .active
      color: $lightblue

  span.cart-text:before
    margin: 5px
    
    > span
      display: block
      
  /* Quantity Notification */  
  
  span.cart-quantity
    position: relative
    top: -2px
    left: 5px
    display: inline-block
    width: 22px
    height: 22px
    border-radius: 50%
    background: #f63
    font-size: .6em
    line-height: 20px
    text-align: center
    color: $white

  /* Quantity Notification hidden when no items*/  
  
  .cart-quantity.empty
    display: none
    
  /* Back button hidden by default */    
  
  .returnToShop
    display: none  

  /* State changes when cart is active */  
  
  a.cart-link.active
    border: 0
    
    /* Cart link gets hidden*/  
    
    span.cart-text
      display: none
      
    span.cart-quantity
      display: none      
      
    /* Back button is displayed */ 
    
    span.returnToShop
      position: absolute
      right: -75px
      display: block
      padding: 0 10px
      background: lighten($black, 5%)
      border-right: 1px dotted lighten($black, 20%)       
      
      
/* Sliding Cart
   ============================ */

.wrap 
  position: relative
  right: 0
  box-shadow: 10px -10px 20px -10px rgba(0,0,0,.8)
  transition: all 200ms ease-out

.wrap.active 
  right: 18em

#cart
  clear: both
  overflow: hidden

.js #cart 
  position: absolute
  top: 0
  right: 0
  width: 18em
  height: 100%

  
/* Footer
   ============================ */

footer
  clear:both
  background: $black
  font-size: .85em
  color: #fff

  p
    margin: 0 1em
    line-height: 3em
    color: $gray

    
/* Shop & Product Items
   ============================ */

section.shop

.product
  position: relative
  z-index: 1
  float: left
  width: 50%
  height: 300px
  overflow: hidden
  background-position: center center
  background-size: cover
  
  /* Hide product descriptions */
  
  > *
    margin: 20px 25px
    opacity: 0
    transition: opacity 200ms ease-out  
  
  /* On hover, adds overlay on top of product image */
  
  &:hover:before
    position: absolute
    z-index: -1
    top: 0
    display: inline-block
    width: 100%
    height: 300px
    background: rgba(0,0,0,.8)
    content: ''

  /* On hover, fade in product descriptions */
  
  > *
    margin: 20px 25px
    opacity: 0
    transition: opacity 200ms ease-out    
  &:hover > *, .active
    opacity: 1

  /* Styles for each shop item */  
  h1
    padding: 15px 0
    border-bottom: 1px dotted darken($white, 50%)
    font-weight: normal
    font-size: 1.6em
    color: $blue

  p
    margin-bottom: 30px
    line-height: 1.5em

  /* "Add to Cart" Buttom with 3D transforms and keyframe animation (Works best in Chrome) */
  
  .button
    position: relative
    display: block
    width: 150px
    height: 50px
    text-align: center
    perspective: 1000px

    .price
      position: absolute
      z-index: 1
      top: 2px
      display: block
      width: 50px
      height: 46px
      border-right: 1px solid $lightblue
      border-radius: 2px 0 0 2px
      background: $white
      line-height: 45px
      color: $gray
      transform: rotateY(0deg) translateZ(25px)

    /* Button magic */    
    
    .addtocart
      position: absolute
      left: 48px
      width: 100%
      height: 100%
      transform-style: preserve-3d
      transform: translateZ( -100px )
      transition: transform 300ms
      cursor: pointer

      > div
        position: absolute
        display: block
        width: 150px
        height: 50px
        border-radius: 0 2px 2px 0 
        line-height: 50px

      > .add
        background: $white
        color: $blue
        transform: rotateY(0deg) translateZ(25px)
        transition: background 150ms ease-out

        &:hover
          background: $blue    
          color: $white        

      > .added
        background: #f63
        color: $white
        transform: rotateX(90deg) translateZ(25px)

      &.active
        animation-name: rotate
        animation-duration: 1s


/* Cart & Cart Items
   ============================ */

#cart
  background: #222

#cart>h2
  height: 64px
  padding-right: 1em
  border-left: 1px dotted $gray 
  border-bottom: 1px solid $blue
  margin: 0
  background: #2d2d2d
  font-weight: normal
  font-size: 1.2em
  text-align: right
  line-height: 64px

/* Styles for each cart item */

.cart-items
  padding: 0  
  
.cart-items > li

  margin: 30px 20px 30px
  border: 1px solid #333  
  background: #202020
  list-style: none
  
.cart-product
  position: relative
  display: inline-block
  height: 75px
  width: 75px
  background-image: url('https://cdn.shopify.com/s/files/1/0051/4802/products/MG_1785_1024x1024.jpg')
  background-size: cover
  vertical-align: top

  input.quantity
    width: 75px
    height: 75px
    padding: 0
    border: 0
    border-right: 1px solid #333
    background: rgba(0,0,0,.5)
    font-size: 2.5em
    line-height: 75px
    text-align: center
    color: $white

.cart-description
  display: inline-block
  height: 75px
  width: 160px
  margin-left: 10px
  text-align: right
  vertical-align: top  

  h3
    margin: 8px
    font-size: 1em
    color: $blue

  .subtotal
    position: relative
    display: inline-block
    margin: 8px    
    font-size: .8em

/* Styling for Total Costs */      

.total
  margin-top: 50px

.total > *
  display: block
  padding-bottom: 10px
  margin: 0 20px 10px 20px
  font-size: .8em
  text-align: left

.total span
  float: right
  text-align: right

.subtotalTotal
  border-bottom: 1px dotted $gray

.shipping
  border-bottom: 1px dotted $gray   

.finalTotal
  font-size: 1em
  color: $blue

a.checkout
  height: 35px
  padding: 0
  margin-top: 30px
  border-radius: 3px
  background: $darkblue
  font-size: 1em
  text-align: center
  text-transform: uppercase
  line-height: 35px
  transition: background 150ms ease-out
  cursor: pointer
  
  &:hover
    background: darken($blue, 15%)
  &.active
    animation-name: shake
    animation-duration: 800ms  
.error
  display: none
  text-align: center
.error:after
  display: block
  font-size: .9em
  text-transform: none
  content: "Sorry, the Octocat is busy!"
    
  
/* Media Queries
   ============================ */

@media (max-width: 720px)
  .product
    width: 100%

@media (max-width: 420px)
  
  /* Hide text in the cart link to save room */
  .cart-text>span
    display: none
    
    
/* Keyframe Animations
   ============================ */
        
@keyframes rotate
  35%
    transform: translateZ(-100px) rotateX(-90deg)
  72%
    transform: translateZ(-100px) rotateX(-90deg)  
  100%
    transform: translateZ(-100px)

@keyframes shake
  0%, 100%
    transform: translateX(0)
  10%, 30%, 50%, 70%, 90%
    transform: translateX(-5px)
  20%, 40%, 60%, 80%
    transform: translateX(5px)    
            
          
!
            
              $(document).ready(function() {

  // Product data to be used in shop and in cart
  var products = {
    'Octocat Mug' : ['Octocat Mug', "The mug you've been dreaming about. One sip from this ceramic 16oz fluid delivery system and you'll never go back to red cups.", 14, 'https://cdn.shopify.com/s/files/1/0051/4802/products/white-mug-1_1024x1024.jpg', 1],
    'Leather Coasters' : ['Leather Coasters', "These coasters roll all of the greatest qualities into one: class, leather, and octocats. They also happen to protect surfaces from cold drinks.", 18, 'https://cdn.shopify.com/s/files/1/0051/4802/products/MG_1934_1024x1024.jpg', 2],  
    'Octopint (Set of 2)' : ['Octopint (Set of 2)', "Set of two heavyweight 16 oz. Octopint glasses for your favorite malty beverage.", 16, 'https://cdn.shopify.com/s/files/1/0051/4802/products/pint_1024x1024.jpg', 3],
    'Blacktocat 2.0 Tee' : ['Blacktocat 2.0 Tee', "Check it. Blacktocat is back with a whole new direction. He's exited stealth mode and is ready for primetime, now with a stylish logo.", 25, 'https://cdn.shopify.com/s/files/1/0051/4802/products/blacktocat-3_1024x1024.jpg', 4],
    'Die Cut Stickers' : ['Die Cut Stickers', "Need a huge Octocat sticker for your laptop, fridge, snowboard, or ceiling fan? Look no further!", 2, 'https://cdn.shopify.com/s/files/1/0051/4802/products/sticker-large_1024x1024.jpg', 5],
    'Pixelcat Shirt' : ['Pixelcat Shirt', "Pixels are your friends. Show your bits in this super-comfy blue American Apparel tri-blend shirt with a pixelated version of your favorite aquatic feline", 25, 'https://cdn.shopify.com/s/files/1/0051/4802/products/8bit-1_1024x1024.jpg?145', 6]
  };  
  
  // Populates shop with items based on template and data in var products
  
  var $shop = $('.shop');
  var $cart = $('.cart-items');
  
  for(var item in products) {
    var itemName = products[item][0],
        itemDescription = products[item][1],
        itemPrice = products[item][2],
        itemImg = products[item][3],
        itemId = products[item][4],
        $template = $($('#productTemplate').html());
    
    $template.find('h1').text(itemName);
    $template.find('p').text(itemDescription);
    $template.find('.price').text('$' + itemPrice);
    $template.css('background-image', 'url(' + itemImg + ')');
    
    $template.data('id', itemId);
    $template.data('name', itemName);
    $template.data('price', itemPrice);
    $template.data('image', itemImg);
    
    $shop.append($template);
  }
  
  // Checks quantity of a cart item on input blur and updates total
  // If quantity is zero, item is removed
  
  $('body').on('blur', '.cart-items input', function() {
    var $this = $(this),
        $item = $this.parents('li');
    if (+$this.val() === 0) {
      $item.remove();
    } else {
      calculateSubtotal($item);
    }
    updateCartQuantity();
    calculateAndUpdate();
  });
  
  // Add item from the shop to the cart
  // If item is already in the cart, +1 to quantity
  // If not, creates the cart item based on template
  
  $('body').on('click', '.product .add', function() {
    var items = $cart.children(),
        $item = $(this).parents('.product'),
        $template = $($('#cartItem').html()),
        $matched = null,
        quantity = 0;
    
    $matched = items.filter(function(index) {
      var $this = $(this);
      return $this.data('id') === $item.data('id');
    });
   
    if ($matched.length) {
      quantity = +$matched.find('.quantity').val() + 1;
      $matched.find('.quantity').val(quantity);
      calculateSubtotal($matched);
    } else {
      $template.find('.cart-product').css('background-image', 'url(' + $item.data('image') + ')');
      $template.find('h3').text($item.data('name'));
      $template.find('.subtotal').text('$' + $item.data('price'));
    
      $template.data('id', $item.data('id'));
      $template.data('price', $item.data('price'));
      $template.data('subtotal', $item.data('price'));
      
      $cart.append($template);
    }
    
    updateCartQuantity();
    calculateAndUpdate();
  });

  // Calculates subtotal for an item
  
  function calculateSubtotal($item) {
    var quantity = $item.find('.quantity').val(),
        price = $item.data('price'),
        subtotal = quantity * price;
    $item.find('.subtotal').text('$' + subtotal);
    $item.data('subtotal', subtotal);
  } 
    
  // Clicking on the cart link opens up the shopping cart
  
  var $cartlink = $('.cart-link'), $wrap = $('#wrap');
  
  $cartlink.on('click', function() {
    $cartlink.toggleClass('active');
    $wrap.toggleClass('active');
    return false;    
	});
  
  // Clicking outside the cart closes the cart, unless target is the "Add to Cart" button 
 
  $wrap.on('click', function(e){
    if (!$(e.target).is('.add')) {
      $wrap.removeClass('active');
      $cartlink.removeClass('active');
    }
  });
 
  // Calculates and updates totals, taxes, shipping
  
  function calculateAndUpdate() {
    var subtotal = 0,
        items = $cart.children(),
        // shipping not applied if there are no items
        shipping = items.length > 0 ? 5 : 0,
        tax = 0;
    items.each(function(index, item) {
      var $item = $(item),
          price = $item.data('subtotal');
      subtotal += price;
    });
    $('.subtotalTotal span').text(formatDollar(subtotal));
    tax = subtotal * .05;
    $('.taxes span').text(formatDollar(tax));
    $('.shipping span').text(formatDollar(shipping));
    $('.finalTotal span').text(formatDollar(subtotal + tax + shipping));
  }

  //  Update the total quantity of items in notification, hides if zero
  
  function updateCartQuantity() {
    var quantities = 0,
        $cartQuantity = $('span.cart-quantity'),
        items = $cart.children();
    items.each(function(index, item) {
      var $item = $(item),
          quantity = +$item.find('.quantity').val();
      quantities += quantity;
    });
    if(quantities > 0){
      $cartQuantity.removeClass('empty');
    } else {
      $cartQuantity.addClass('empty');
    }
    $cartQuantity.text(quantities);
  }
  
 
  //  Formats number into dollar format
     
  function formatDollar(amount) {
    return '$' + parseFloat(Math.round(amount * 100) / 100).toFixed(2);
  }
  
  // Restrict the quantity input field to numbers only
     
  $('body').on('keypress', '.cart-items input', function (ev) {
      var keyCode = window.event ? ev.keyCode : ev.which;
      if (keyCode < 48 || keyCode > 57) {
        if (keyCode != 0 && keyCode != 8 && keyCode != 13 && !ev.ctrlKey) {
          ev.preventDefault();
        }
      }
    });
  
  // Trigger animation on Add to Cart button click
  
  $('.addtocart').on('click', function () {
    $(this).addClass('active');
    setTimeout(function () {
      $('.addtocart').removeClass('active');    
    }, 1000);
  });
  
  // Trigger error animation on Checkout button
  
  $('.checkout').on('click', function () {
    $(this).addClass('active');
    $('.error').css('display', 'block');
    setTimeout(function () {
      $('.checkout').removeClass('active');    
      $('.error').css('display', 'none');      
    }, 1000);
  });    
  
});
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console