JSFiddle - React, Tailwind, and code Playground

by tonyleeper

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<section data-bind="onDocumentClick: hideOverflowList">
    <nav tabindex="0">
        <ul class="tabs" data-bind="tabs: tabs">
            <li data-bind="css: { active: active, fixed: fixed }">
                <div data-bind="event: { mousedown: $root.activateTab.bind($root) }"> 
                    <span data-bind="text: name"></span>
                </div>
            </li>
        </ul>
        <div class="overflow" data-bind="visible: tabsOverflowing, event: { mousedown: toggleOverflowList }, preventEventBubbling: 'click'"> 
            <i>...</i>
        </div>
        <ul class="overflow" data-bind="visible: overflowListActive, foreach: tabs">
            <li data-bind="css: { active: active, fixed: fixed }">
                <div data-bind="click: $root.activateTab.bind($root)"> <span data-bind="text: name"></span>

                </div>
            </li>
        </ul>
    </nav>
    <!-- TODO: use nighthawk to data bind this article to the dashboard view -->
    <!-- ko foreach: tabs -->
    <article class="active" data-bind="visible: active"> <span class="dashboard-name" data-bind="text: name"></span>

    </article>
    <!-- /ko -->
</section>

CSS

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
html, body {
    height: 100%;
}
body {
    font-family: arial;
    background-color: #5f6570;
    padding: 15px;
}
section {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 400px;
    min-width: 500px;
}
ul.tabs {
    height: 70px;
    list-style: none;
    font-size: 0;
    flex: 1 1;
    padding-left: 10px;
    -webkit-transform: translateZ(0); /* faster repaints */
}
ul.tabs > li {
    display: inline-block;
    vertical-align: top;
    margin-right: 10px;
    margin-bottom: 10px;
    /* we don't want to see the overflowing tabs across the bottom */
}
ul.tabs > li > div {
    font-family: arial;
    font-weight: normal;
    font-size: 16px;
    color: #fff;
    text-shadow: 0 1px #000;
    display: inline-block;
    height: 60px;
    line-height: 60px;
    text-align: center;
    width: 100px;
    background-color: #454a51;
    border: 0;
    border-radius: 3px;
    padding: 0 10px;
}
ul.tabs > li.fixed > div {
    width: 150px;
}
ul.tabs > li.fixed:not(.active) > div {
    border: 1px solid black;
    box-shadow: inset 0px 0px 0px 1px rgba(255,255,255,0.4)
}
ul > li > div > span {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
ul.tabs > li.active > div {
    position: relative;
    font-size: 18px;
    color: #454b54;
    text-shadow: 0 1px #fff;
    background-color: #fff;
    height: 70px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}
ul.tabs > li.active > div:before {
    content:"";
    display: block;
    position: absolute;
    left: -6px;
    bottom: 0;
    width: 6px;
    height: 6px;
    background-color: #5f6570;
    border-bottom-right-radius: 4px;
}
ul.tabs > li.active > div:after {
    content:"";
    display: block;
    position: absolute;
    right: -4px;
    bottom: -1px;
    width: 5px;
    height: 5px;
    background-color: #fff;
}
ul.tabs > li.active {
    position:...

JavaScript

Array.prototype.swap = function (i, j) {
  var temp = this[i];
  this[i] = this[j];
  this[j] = temp;
  return this;
};

/**
    carbon2 tabs
*/

/**
    Prevents specific events from bubbling
    Syntax:  data-bind="preventEventBubbling: 'click'"
             OR
             data-bind="preventEventBubbling: ['click', 'onchange',.....]"
*/
ko.bindingHandlers.preventEventBubbling = {
    stopPropagation: function (event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else { // Older IE.
            event.cancelBubble = true;
        }
    },

    init: function (element, valueAccessor) {
        var $element = $(element);
        var binding = ko.utils.unwrapObservable(valueAccessor());

        if (typeof binding === "string") {
            $element.on(binding, ko.bindingHandlers.preventEventBubbling.stopPropagation);
        } else if (Array.isArray(binding)) {
            for (var i = 0; i < binding.length; i++) {
                $element.on(binding[i], ko.bindingHandlers.preventEventBubbling.stopPropagation);
            }
        }
    }
};

/**
    Custom binding handler that executes custom logic on document click
*/
ko.bindingHandlers.onDocumentClick = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // First get the latest data that we're bound to
        var allBindings = allBindingsAccessor();

        $(document).on('click', function () {
            allBindings.onDocumentClick.call(viewModel);
            return true;
        });
    }
};

/**
    sdl draggable plugin
*/
(function ($) {
    var normalizeEvent = function (event) {
        // "normalize" the event so that the passed in drag handler doesn't have to worry about
        if (false) {
            event.pageX = event.originalEvent.touches[0].pageX;
            event.pageY = event.originalEvent.touches[0].pageY;
            event.clientX = event.originalEvent.touches[0].clientX;
            event.clientY =...