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
// http://css3.bradshawenterprises.com/transforms/
var utils = {
/**
String utility methods
*/
string: {
/**
Capitalizes a string
@param {string} value The string value to capitalize
*/
capitalize: function (value) {
return value.charAt(0).toUpperCase() + value.slice(1);
},
/**
Returns true if the value is null or an empty string, otherwise returns false
@param {string} string The string value to test
@return {boolean} true if value is null or an empty string, otherwise false
*/
isNullOrEmpty: function (value) {
return value === null || value === "";
},
/**
Returns true if the string starts with the supplied value
@param {string} string The string to test
@param {string} value The value to look for at the start of the string
*/
startsWith: function (string, value) {
return string.slice(0, string.length) === value;
},
/**
Returns true if the string ends with the supplied value
@param {string} string The string to test
@param {string} value The value to look for at the end of the string
*/
endsWith: function (string, value) {
return string.slice(string.length - value.length) === value;
}
},
/**
Array utility methods
*/
array: {
/**
returns the index of the first element that satisfies the predicate condition
@param {array} the array to search
@param {function} predicate The predicate function to test against each element
*/
firstIndexWhere: function...