Pen Settings

HTML

CSS

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

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!-- Place this tag in your head or just before your close body tag. -->
<script async defer src="https://buttons.github.io/buttons.js"></script>

<div class="wrapper">
  <header class="clear">
    <ul>
      <li>Rejected</li>
      <li>Pending</li>
      <li>Development</li>
      <li>Testing</li>
      <li>Production</li>
    </ul>
  </header>
  <section id="dashboard" class="dashboard clear">
    <div id="rejected" class="rejected"></div>
    <div id="pending" class="pending"></div>
    <div id="development" class="development"></div>
    <div id="testing" class="testing"></div>
    <div id="production" class="production"></div>
  </section>

  <footer>
    <ul>
      <li class="branding">Scrum <span>Board</span> <sup>Beta</sup></li>
    </ul>

    <ul class="controls">
      <li>
        <a target="_blank" class="twitter-share-button" href="https://twitter.com/intent/tweet?text=Scrum%20Board%2C%20Simple%20Task%20Manager%20App.%20Powered%20by%20JavaScript.%20Checkout%20now%20on%20CodePen%20https%3A%2F%2Fgoo.gl%2FtTkZGO">
Tweet</a>
      </li>
      <li>
        <a class="github-button" href="https://github.com/i-break-codes/scrum-board" data-icon="octicon-star" data-count-href="/i-break-codes/scrum-board/stargazers" data-count-api="/repos/i-break-codes/scrum-board#stargazers_count" data-count-aria-label="# stargazers on GitHub" aria-label="Star i-break-codes/scrum-board on GitHub">Star</a>
      </li>
      <li>
        <a class="github-button" href="https://github.com/i-break-codes/scrum-board/archive/master.zip" data-icon="octicon-cloud-download" aria-label="Download i-break-codes/scrum-board on GitHub">Download</a>
      </li>
      <li data-tooltip="Drag A Task Here To Delete">
        <a href="#" class="remove" id="remove">
          <img src="http://imgh.us/bin_1.svg" alt="">
        </a>
      </li>
      <li data-tooltip="Add Task">
        <a href="#" id="add-task" class="add-task">
          <img src="http://imgh.us/plus_13.svg" alt="">
        </a>
      </li>
      <li data-tooltip="Github" class="github-ref">
        <a href="https://github.com/i-break-codes/scrum-board" target="_blank">
          <img src="http://imgh.us/github_6.svg" alt="">
        </a>
      </li>
    </ul>
  </footer>
</div>

<div id="removed-task-notification" class="removed-task-notification hide"></div>

<div class="modal hide" id="add-task-modal">
  <div class="modal-wrapper">
    <form action="index.html" method="post" class="add-task-form" name="add_task">
      <span class="close-modal">X</span>

      <h3>Add a new Task</h3>

      <ul>
        <li>
          <input type="text" name="title" placeholder="Title" autofocus>
        </li>
        <li>
          <textarea name="description" placeholder="Description"></textarea>
        </li>
        <li>
          <input type="text" name="remote_url" placeholder="Remote Task URL">
        </li>
        <li>
          <input type="text" name="assigned_to" placeholder="Assigned To">
        </li>
        <li>
          <input type="submit" name="create_task" value="Create Task">
        </li>
      </ul>
    </form>
  </div>

  <div class="create-task-branding">
    Scrum <span>Board</span> <sup>Beta</sup>
  </div>
</div>

<div class="hide" id="tips">
  Double click on the task text to edit it <br> <span>(Task titles are not editable for now)</span>
</div>

<script id="task-card-template" type="text/x-handlebars-template">
  {{#each this}}
  <div class="card" data-task-id="{{id}}">
    <a href="#" class="expand-card"></a>
    <h5>{{title}}</h5>
    <div class="card-details">
      <p data-field="description">{{description}}</p>
      <p data-field="remote_url">
        {{#checkIfEmptyRemoteURL remote_url}}{{/checkIfEmptyRemoteURL}}
      </p>
      <p data-field="assigned_to">
        {{#checkIfEmptyAssigned assigned_to}}{{/checkIfEmptyAssigned}}
      </p>
    </div>
  </div>
  {{/each}}
</script>

              
            
!

CSS

              
                @import 'https://fonts.googleapis.com/css?family=Hind+Vadodara:300,400';
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400');

//Colors

$base-color: rgba(0,0,0,.4);
$primary-color: #fff;
$secondary-color: rgba(255,255,255,.1);

$grad-start: #000428;
$grad-end: #004e92;

* {
  margin: 0;
  padding: 0;
  outline: 0;
  box-sizing: border-box;
}

html, body, .wrapper {
  height: 100%;
}

body {
  font-weight: 300;
  font-family: Hind Vadodara;
  background-image: linear-gradient(to left, $grad-start, $grad-end);
  color: $primary-color;
  font-size: 14px;
}

ul {
  list-style-type: none;
}

a {
  text-decoration: none;
  color: inherit;
}

.clear {
  &:after {
    content: "";
    display: table;
    clear: both;
  }
}

.hide {
  display: none !important;
}

header {
  background-color: $base-color;
  
  li {
    padding: 15px;
    float: left;
    width: 20%;
    text-align: center;
    position: relative;
    text-transform: uppercase;
    
    &:after {
      content: "";
      position: absolute;
      left: 0;
      bottom: 0;
      width: 100%;
      height: 1px;
    }
    
    &:nth-child(1) {
      &:after {
        background: linear-gradient(to left, #cb2d3e , #ef473a);
      }
    }
    
    &:nth-child(2) {
      &:after {
        background: linear-gradient(to left, #ffb347 , #ffcc33);
      }
    }
    
    &:nth-child(3) {
      &:after {
        background: linear-gradient(to left, #56ab2f , #a8e063);
      }
    }
    
    &:nth-child(4) {
      &:after {
        background: linear-gradient(to left, #00d2ff , #3a7bd5);
      }
    }
    
    &:nth-child(5) {
      &:after {
        background: linear-gradient(to left, #4CB8C4 , #3CD3AD);
      }
    }
  }
}

.wrapper {
  overflow: hidden;
}


//dashboard
.dashboard {
  height: calc(100% - 101px);

  > div {
    float: left;
    height: 100%;
    border-right: 1px solid $base-color;
    width: 20%;
  }
}


//Cards
.card {
  background-color: $base-color;
  min-height: 50px;
  margin: 10px;
  position: relative;
  overflow: hidden;
  height: 40px;
  box-shadow: 3px 3px 3px rgba(0,0,0,.1);
  z-index: 2;
  
  &:before {
    content: "";
    position: absolute;
    height: 100%;
    width: 1px;
  }
  
  p:before,
  h5:after {
    .rejected & {
      color: #ef473a;
    }
    
    .pending & {
      color: #ffcc33;
    }
    
    .development & {
      color: #a8e063;
    }
    
    .testing & {
      color: #3a7bd5;
    }
    
    .production & {
      color: #3CD3AD;
    }
  }
  
  h5 {
    font-size: 13px;
    line-height: 50px;
    padding-left: 10px;
    font-weight: 300;
  }
  
  &.edit-mode {
    h5 {
      position: relative;
      
      &:after {
        top: 50%;
        margin-left: 5px;
        margin-top: 1px;
        transform: translateY(-50%);
        position: absolute;
        font-size: 9px;
        content: "(Edit Mode Enabled)";
      }
    }
  }
  
  .rejected & {
    &:before {
      background: linear-gradient(to left, #cb2d3e , #ef473a);
    }
  }
  
  .pending & {
    &:before {
      background: linear-gradient(to left, #ffb347 , #ffcc33);
    }
  }
  
  .development & {
    &:before {
      background: linear-gradient(to left, #56ab2f , #a8e063);
    }
  }
  
  .testing & {
    &:before {
      background: linear-gradient(to left, #00d2ff , #3a7bd5);
    }
  }
  
  .production & {
    &:before {
      background: linear-gradient(to left, #4CB8C4 , #3CD3AD);
    }
  }
  
  &.expanded {
    overflow: auto !important;
    height: auto !important;
  }
}

.card-details {
  padding: 10px;
  font-size: 12px;
  word-wrap: break-word;
  padding-top: 0;
  
  p {
    margin-bottom: 10px;
    position: relative;
    
    &:before {
      position: absolute;
      left: 0;
    }
    
    &:nth-child(1) {
      padding-left: 67px;
      
      &:before {
        content: "Description : ";
      }
    }
    
    &:nth-child(2) {
      padding-left: 72px;
      
      &:before {
        content: "Remote URL : ";
      }
    }
    
    &:nth-child(3) {
      padding-left: 70px;
      
      &:before {
        content: "Assigned To : ";
      }
    }
  }
  
  a {
    border-bottom: 1px dotted #fff;
    
    &:hover {
      border-bottom-style: solid;
    }
  }
}

.dragged-over {
  background-color: rgba(0,0,0,.1);
}

@keyframes rotate180 {
  to {
    transform: rotate(180deg);
  }
}


.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-image: linear-gradient(to left, $grad-start, $grad-end);
  z-index: 2;
}

.modal-wrapper {
  position: absolute;
  top: 50%;
  left: 50%;
  max-width: 400px;
  margin: auto;
  width: 100%;
  transform: translateX(-50%) translateY(-50%);
  
  .close-modal {
    border: 1px solid rgba(255,255,255,.1);
    border-radius: 50%;
    width: 50px;
    height: 50px;
    position: absolute;
    top: -90px;
    font-family: Open Sans;
    line-height: 52px;
    font-size: 20px;
    left: 50%;
    transform: translateX(-50%);
    vertical-align: middle;
    cursor: pointer;
    
    &:hover {
      border-color: #fff;
    }
  }
  
  h3 {
    font-weight: 100;
    font-size: 30px;
    position: relative;
  }
}

.add-task-form {
  text-align: center;
  
  li {
    margin-top: 30px;
  }
  
  [type=text],
  [type=submit],
  textarea {
    color: #fff;
    font-size: inherit;
    font-family: inherit;
    font-weight: inherit;
    width: 100%;
    line-height: 24px;
    padding: 15px 10px;
    appearance: none;
    border: 1px solid rgba(255,255,255,.07);
    background-color: transparent;
    transition: border-color .25s linear;
    
    &::-webkit-input-placeholder {
      color: rgba(255,255,255,.3);
    }
    
    &:focus {
      border-color: #fff;
    }
  }
  
  [type=submit] {
    cursor: pointer;
    border-color: transparent;
  }
  
  textarea {
    resize: none;
    min-height: 100px;
  }
}

.expand-card {
  height: 19px;
  width: 19px;
  background-size: auto 100%;
  display: inline-block;
  position: absolute;
  top: 25px;
  cursor: pointer;
  transform: translateY(-50%);
  right: 15px;
  padding: 3px;
  
  .rejected & {
    background-image: url('http://imgh.us/rejected-expand.svg');
  }
  
  .pending & {
    background-image: url('http://imgh.us/pending-expand.svg');
  }
  
  .development & {
    background-image: url('http://imgh.us/development-expand.svg');
  }
  
  .testing & {
    background-image: url('http://imgh.us/testing-expand.svg');
  }
  
  .production & {
    background-image: url('http://imgh.us/production-expand.svg');
  }
  
  svg {
    fill: #fff;
  }
}

.removed-task-notification {
  position: absolute;
  top: 10%;
  left: 50%;
  transform: translateX(-50%);
  padding: 5px 20px;
  color: #515151;
  border-radius: 3px;
  background-color: rgba(255,255,255,.8);
  box-sizing: 0 0 3px rgba(0,0,0,.6);
}

footer {
  height: 50px;
  position: relative;
  border-top: 1px solid $base-color;
}

.remove {
  display: block;
  background-color: #ef473a;
  border-radius: 50%;
  height: 30px;
  width: 30px;
  text-align: center;
  padding-top: 7px;
  transition: all 300ms ease-out;
  cursor: default;

  img {
    width: 16px;
  }
  
  &.dragged-over {
    width: 250px;
    border-radius: 3px;
  }
}

.add-task {
  z-index: 1;
  border-radius: 50%;
  
  img {
    width: 30px;
    display: block;
    box-shadow: 3px 3px 3px rgba(0,0,0,.1);
  }
  
  &:hover {
    img {
      animation: rotate180 .2s linear;
    }
  }
}

[data-tooltip] {
  position: relative;
  
  &:before {
    display: none;
    content: attr(data-tooltip);
    background-color: rgba(0,0,0,.6);
    padding: 10px 20px;
    position: absolute;
    text-align: center;
    white-space: nowrap;
    left: 50%;
    transform: translateY(-130%) translateX(-50%);
  }
  
  &:hover {
    &:before {
      display: block;
    }
  }
}

.controls {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  
  li {
    float: left;
    margin-right: 20px;
  }
}

.branding,
.create-task-branding {
  text-transform: uppercase;
  font-size: 18px;
  padding: 15px;
  float: left;
  position: relative;
  
  sup {
    position: absolute;
    font-size: 9px;
    right: 5px;
    top: 10px;
  }
  
  span {
    color: rgba(255,255,255,.6);
  }
}

.create-task-branding {
  position: absolute;
  bottom: 2px;
  left: 0;
  width: 150px;
}

.github-ref {
  height: 30px;
  width: 30px;
  
  img {
    height: 29px;
    width: 29px;
  }
}

.onboard {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, .7);
  z-index: 2;
}

.onboard-modal {
  height: 300px;
  width: 450px;
  background-color: #fff;
  border-radius: 3px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.tips {
  position: absolute;
  bottom: 90px;
  right: -280px;
  font-size: 13px;
  background-color: rgba(0,0,0,.3);
  padding: 10px;
  border-radius: 3px;
  padding-left: 25px;
  opacity: 0;
  animation: showTips 500ms ease-in forwards;
  cursor: pointer;
  background: {
    image: url('http://imgh.us/info_12.svg');
    position: 4px 12px;
    size: 16px;
    repeat: no-repeat;
  }
  
  span {
    font-size: 10px;
    font-style: italic;
  }
}

@keyframes showTips {
  to {
    right: 20px;
    opacity: 1;
  }
}

iframe {
  margin-top: 5px;
}

.twitter-share-button {
  background-color: #1b95e0;
  padding: 4px 10px;
  font-size: 12px;
  border-radius: 3px;
  vertial-align: middle;
  position: absolute;
  top: 4px;
  left: -70px;
}
              
            
!

JS

              
                /**
 * @category   scrum-board
 * @author     Vaibhav Mehta <vaibhav@decodingweb.com>
 * @copyright  Copyright (c) 2016 Vaibhav Mehta <https://github.com/i-break-codes>
 * @license    https://www.opensource.org/licenses/mit-license.html  MIT License
 * @version    1.0 Beta
 */


var LocalStorage = function() {
  function set(key, val) {
    localStorage.setItem(key, val);
  }
  
  function get(key) {
    return localStorage.getItem(key);
  }
  
  function remove(key) {
    localStorage.removeItem(key);
  }
  
  return {
    set: set,
    get: get,
    remove: remove
  }
}();

// TODO: Clearup this mess later and find a better way to handle blank fields

var Helper = function() {
  function init() {
    checkIfEmptyRemoteURL();
    checkForEmptyAssign();
  }
  
  function checkIfEmptyRemoteURL() {
    Handlebars.registerHelper('checkIfEmptyRemoteURL', function(val, options) {
      if(val) {
        return '<a href="' + val + '" target="_blank">' + val + '</a>';
      } else {
        return '-';
      }
    });
  }
  
  function checkForEmptyAssign() {
    Handlebars.registerHelper('checkIfEmptyAssigned', function(val, options) {
      if(val) {
        return val;
      } else {
        return '-';
      }
    });
  }
  
  return {
    init: init
  }
}();

Helper.init();

var App = function() {
  function init() {
    tips();
    preset();
    draggable();
    droppable();
    openCard();
    createTask();
    closeModal();
    printNotes();
    editTask();
    exitEditMode();
  }
  
  function preset() {
    $('#remove').on('click', function(e) {
      e.preventDefault();
    });
    
    var defaultTask = {
      id: 1,
      title: 'This is a sample task',
      description: 'Sample tasks are useful to get started',
      remote_url: 'https://asana.com/12345/1234',
      assigned_to: 'Jon Doe',
      status: 'pending'
    }
    
    if(!LocalStorage.get('appInitialized', true)) {
      LocalStorage.set('taskCounter', 1);
      LocalStorage.set('task-1', JSON.stringify(defaultTask));
      LocalStorage.set('appInitialized', true);
    }
  }
  
  function createTask() {
    var source = $("#task-card-template").html();
    var template = Handlebars.compile(source);
    
    $('#add-task').on('click', function(e) {
      e.preventDefault();
      $('#add-task-modal').removeClass('hide');
      
      $('#add-task-modal').find('form').on('submit', function(e) {
        e.preventDefault();
        var obj = {};
        var params = $(this).serialize();
        var splitParams = params.split('&');
        
        for(var i = 0, l = splitParams.length; i < l; i++) {
          var keyVal = splitParams[i].split('=');
          obj[keyVal[0]] = unescape(keyVal[1]);
        }

        // TODO: Add validations
        if(obj.description === '' || obj.title === '') {
          return;
        }
        
        var iid = LocalStorage.get('taskCounter');
        obj.id = ++iid;
        obj.status = 'pending';
        LocalStorage.set('task-' + obj.id, JSON.stringify(obj));
        LocalStorage.set('taskCounter', iid);
        
        var newCard = template([obj]);
        $('#dashboard #' + obj.status).append(newCard);
        draggable();
        
        $('.close-modal').trigger('click');
        
        //Clear form fields after submit
        $(this).find('input[type=text], textarea').val('');
      });
      
    });
  }
  
  function editTask() {
    $(document).on('dblclick', '.card-details p', function(e) {
      e.stopPropagation();
      $(this).attr('contenteditable','true').parents('.card').addClass('edit-mode');
    });
    
    $(document).on('input', '.card p', function() {
      var taskId = $(this).parents('.card').data('task-id');
      var fieldToEdit = $(this).data('field');
      var getTaskData = JSON.parse(LocalStorage.get('task-' + taskId));
      
      getTaskData[fieldToEdit] = $(this).text();
      
      LocalStorage.set('task-' + taskId, JSON.stringify(getTaskData));
    });
  }
  
  function exitEditMode() {
    $(document).on('dblclick', function(e) {
      $('.card').removeClass('edit-mode').find('[contenteditable]').removeAttr('contenteditable');
    });
  }
  
  function closeModal() {
    $('.close-modal').on('click', function() {
      $('.modal').addClass('hide');
    })
  }
  
  function draggable() {
    $('.card').draggable({
      handle: 'h5',
      revert: true,
      cursor: 'move',
      start: function(event, ui) {
        
      },
      stop: function(event, ui) {
        
      }
    });
  }
  
  function droppable() {
    var droppableConfig = {
      tolerance: 'pointer',
      drop: function(event, ui) {
        var elm = ui.draggable,
            parentId = elm.parent().attr('id'),
            currentId = $(this).attr('id'),
            taskId = elm.data('task-id');
        
        if($(this).attr('id') == 'remove') {
          //Deletes task
          elm.remove();
          LocalStorage.remove('task-' + taskId);
          $('#removed-task-notification').text('Task removed successfully').removeClass('hide');
          
          
          setTimeout(function() {
            $('#removed-task-notification').text('').addClass('hide');
          }, 3000);
        } else {
          //Moves task
          if(parentId != currentId) {
            $(elm).detach().removeAttr('style').appendTo(this);
            
            var getTaskData = JSON.parse(LocalStorage.get('task-' + taskId));
            getTaskData.status = currentId;
            
            LocalStorage.set('task-' + taskId, JSON.stringify(getTaskData));
          }
        }
        
        $(this).removeClass('dragged-over');
      },
      over: function(event, ui) {
        $(this).addClass('dragged-over');
      },
      out: function(event, ui) {
        $(this).removeClass('dragged-over');
      }
    }
    
    $('#dashboard > div, #remove').droppable(droppableConfig);
  }
  
  function openCard() {
    $(document).on('click', '.expand-card', function(e) {
      $(this).parent().toggleClass('expanded');
      e.preventDefault();
    });
  }
  
  function getAllNotes() {
    var getAllData = localStorage;
    var getTasks = [];
    
    for(var data in getAllData) {
      if(data.split('-')[0] == 'task') {
        getTasks.push(JSON.parse(localStorage[data]));
      }
    }
    
    return getTasks;
  }
  
  function printNotes() {
    var source = $("#task-card-template").html();
    var template = Handlebars.compile(source);
    
    var status = ['rejected', 'pending', 'development', 'testing', 'production'];
    
    for(var i = 0, l = status.length; i < l; i++) {
      var result = App.getAllNotes().filter(function(obj) {
        return obj.status == status[i];
      });
      
      if(result) {
        var cards = template(result);
        $('#dashboard #' + status[i]).append(cards);
        draggable();
      }
    }
  }
  
  function tips() {
    if(!JSON.parse(LocalStorage.get('showedTip'))) {
      $('#tips').removeClass('hide').addClass('tips');
    }
    
    $('#tips').on('click', function() {
      $(this).addClass('hide');
      LocalStorage.set('showedTip', true);
    });
  }
  
  return {
    init: init,
    getAllNotes: getAllNotes
  }
}();

App.init();
              
            
!
999px

Console