JSFiddle - React, Tailwind, and code Playground

by tonyleeper

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>

<div class="panel-splitter" data-bind="panelSplitter: { 
    showPanelLeftLabel: 'SHOW LEFTY',
    showPanelRightLabel: 'SHOW RIGHTY',
    leftPanelDefaultWidthPercentage: 60,
    snapToThreshold: 100
}">
    <div class="column-left">
        <div class="content-panel">    
            column1
        </div>
    </div>
    <div class="drag-handle">
        <div class="snap-left draghandle-snapper">&lt;</div>
        <div class="snap-right left-panel-snapper">&gt;</div>
        <div class="grabber"></div>
    </div>
    <div class="column-right">
        <div class="content-panel">    
            column2
        </div>
    </div>
</div>

CSS

* {
    margin: 0;
    padding: 0;
    font-family: arial;
    font-size: 12px;
    
}

body, html {
    height: 100%;
}

.panel-splitter {
    width: 100%;
    height: 100%;
    display: table;
    -webkit-user-select: none;
}

.drag-handle {
    position: relative;
    width: 25px;
    min-width: 25px;
    max-width: 25px;
    background-color: #f0f0f0;
    border-left: 1px solid black;
    border-right: 1px solid black;
    cursor: ew-resize; /* or col-resize ? */
}

.panel-splitter > div {
    display: table-cell;    
}

.column-left, .column-right {
    background-color: #e0e0e0;
    overflow: hidden;
    position: relative;
}

.content-panel {
    position: absolute;
    font-size: 100px;
}

.grabber {
    width: 10px;
    height: 40px;
    background-color: blue;
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
}

.drag-handle > .snap-left, .drag-handle > .snap-right {
    cursor: pointer;
    width: 20px;
    height: 20px;
    background-color: red;
    position: absolute;
}

.left-panel-snapper {
    left: -25px;
    top: 5px;
}

.draghandle-snapper {
    left: 50%;
    top: 5px;
    -webkit-transform: translateX(-50%);    
}

.showPanelLeftLabel, .showPanelRightLabel {
    display: block;
    position: absolute;
    left: 50%;
    top: 30px;
    -webkit-transform-origin: 0 0;
    -webkit-transform: rotate(90deg) translate(0, -50%);
    white-space: nowrap;
}

JavaScript

/**
    panel splitter knockout binding
*/

/**
    Custom plugin for drag support, including support for touch devices
    @param {function} onDrag a callback to invoke on drag
    @param {function} onDragStart an optional function to run on dragStart to determine if dragging should begin
    @param {function} onDragEnd an optional function to run on dragEnd
*/
(function ($) {
    var normalizeEvent = function(event) {
        // "normalize" the event so that the passed in drag handler doesn't have to worry about
        if ('ontouchstart' in window || navigator.msMaxTouchPoints) {
            event.pageX = event.originalEvent.touches[0].pageX;
            event.pageY = event.originalEvent.touches[0].pageY;
            event.clientX = event.originalEvent.touches[0].clientX;
            event.clientY = event.originalEvent.touches[0].clientY;
        }

        return event;
    };

    $.fn.draggable = function (onDrag, onDragStart, onDragEnd) {
        var $document = $(document);

        return this.each(function () {
            var element = this;

            $(this).on("mousedown touchstart", function (event) {
                event = normalizeEvent(event);
                
                if (typeof onDragStart === "function") {
                    if (!onDragStart(event)) {
                        return false;
                    }
                }

                element.dragging = true;
                $(element).addClass("dragging");

                // prevent scrolling on touch devices
                if (event.type === 'touchstart') {
                    return false;
                }

                return true;
            });

            $document.on("mouseup touchend", function (event) {
                if (element.dragging) {
                    element.dragging = false;
                    $(element).removeClass("dragging");
                }
                
                if (typeof onDragEnd === "function") {
                   ...