JSFiddle - React, Tailwind, and code Playground

by George

HTML

<html ng-app="sandboxApp">
<link rel="stylesheet" type="text/css" href="css/styles.css">
<head>
<title>Test Sandbox</title>
</head>
<body>
    <div>This is a sandbox test of a table</div>
    <!--<select ng-model="items_per_page" ng-options="c.id as c.label for c in [{id:'5',label:'5'},{id:'10',label:'10'},{id:'25',label:'25'},{id:'50',label:'50'},{id:'100',label:'100'}]"></select>-->
    <article id="test1" class = "table-frame" ng-controller="newTableCtrl" table-seed-data="data_key" table-show-columns="['age','name','group']" table-set-initial-sort="'group'">
        <span table-paginate-selector="[5,10,25,100]" table-set-initial-pagination="10"></span>
        <span table-search-box></span>
        <table class="data-table">
            <thead>
                <tr>
                    <th ng-repeat="column in columns" ng-click="sortColumn( column )">
                        <span ng-bind="::column"></span>
                        <span ng-show="sort_type == '{{::column}}'" ng-class="sort_reverse ? 'th-caret-up' : 'th-caret-down'"></span>
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="row in table_data() | orderBy:sort_type:sort_reverse | offset: offsetPosition() | limitTo: items_per_page">
                    <td ng-repeat="column in columns">
                        <span ng-bind="row[column]"></span>
                    </td>
                </tr>
            </tbody>
            <tfoot>
                <td colspan="{{::columns.length}}">
                    <div table-pagination-buttons></div>
                    <div table-display-showing-count></div>
                </td>
            </tfoot>
        </table>
    </article>
</body>
<script type="text/javascript" src="static/jquery.min.js"></script>
<script type="text/javascript" src="static/angular.min.js"></script>
<script type="text/javascript" src="static/angular-resource.min.js"></script>
<script type="text/javascript"...

CSS

.th-caret-up:after {
  content: '\2191';
}

.th-caret-down:after {
  content: '\2193';
}

.search-box {
  //font-family: 'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;
  height: 50px;
  background-color: cyan;
  -webkit-transform: rotate(45deg);
     -moz-transform: rotate(45deg); 
       -o-transform: rotate(45deg);
}

.search-box:before {
  //content: '\f002';
  content: '\26B2';
}

.pagination {
  text-align: center;
  ul {
    display: inline-flex;
    padding: 0;
    margin: 0.5em auto;
  }
  .disabled {
    color: #999999;
    //background-color: transparent;
    cursor: default;
    a {
      color: #999999;
    }
  }
  .active {
    background-color: #eeeeff;
  }
  ul > li {
    display: inline;
    border: gray 1px solid;
    background-color: white;
    //border-left-width: 1px;
    padding: 0.2em 0.8em;
    text-align: center;
    min-width: 1.2em;
    &:first-child {
      -webkit-border-top-left-radius: 5px;
      -moz-border-radius-topleft: 5px;
      border-top-left-radius: 5px;
      -webkit-border-bottom-left-radius: 5px;
      -moz-border-radius-bottomleft: 5px;
      border-bottom-left-radius: 5px;
    }
    &:last-child {
      -webkit-border-top-right-radius: 5px;
      -moz-border-radius-topright: 5px;
      border-top-right-radius: 5px;
      -webkit-border-bottom-right-radius: 5px;
      -moz-border-radius-bottomright: 5px;
      border-bottom-right-radius: 5px;
    }
    &:hover {
      background-color: #dfdfdf;
    }
    a {
      //margin: 0.1em;
      min-width: 3em;
      text-decoration: none;
      color: #005580;
      margin-left: auto;
      margin-right: auto;
    }
  }
}
.table-frame {
  background-color: tan;
  width: 80%;
  margin-left: auto;
  margin-right: auto;
  margin-top: 0;
  margin-bottom: 0;
  padding: 1em;
  @include rounded-shadow( tan, blue );
}

.showing-count {
  font-style: italic;
}

.data-table {
  width: 100%;
  margin: 0.2em 0 0.5em 0em;
  border: 1px solid black;
  th, td {
    padding: 0.2 0.5...

JavaScript

// Hard-code the external data
var external_data = [
    { 'name': 'george', 'age': 39, 'group': 'family' },
    { 'name': 'evan', 'age': 44, 'group': 'family' },
    { 'name': 'vasya', 'age': 42, 'group': 'family' },
    { 'name': 'paco', 'age': 12, 'group': 'elgin' },
    { 'name': 'taco', 'age': 13, 'group': 'elgin' },
    
    { 'name': 'elisha', 'age': 20, 'group': 'elgin' },
    { 'name': 'terry', 'age': 21, 'group': 'elgin' },
    { 'name': 'larry', 'age': 33, 'group': 'stooges' },
    { 'name': 'curly', 'age': 32, 'group': 'stooges' },
    { 'name': 'moe', 'age': 34, 'group': 'stooges' },
    
    { 'name': 'shemp', 'age': 35, 'group': 'stooges' },
    { 'name': 'ned', 'age': 56, 'group': 'flanders' },
    { 'name': 'mod', 'age': 54, 'group': 'flanders' },
    { 'name': 'nod', 'age': 14, 'group': 'flanders' },
    { 'name': 'tod', 'age': 15, 'group': 'flanders' },
    
    { 'name': 'homer', 'age': 54, 'group': 'simpsons' },
    { 'name': 'marge', 'age': 53, 'group': 'simpsons' },
    { 'name': 'bart', 'age': 23, 'group': 'simpsons' },
    { 'name': 'lisa', 'age': 19, 'group': 'simpsons' },
    { 'name': 'maggie', 'age': 15, 'group': 'simpsons' },
    
    { 'name': 'knight', 'age': 54, 'group': 'ateam' },
    { 'name': 'baracas', 'age': 53, 'group': 'ateam' },
    { 'name': 'face', 'age': 61, 'group': 'ateam' },
    { 'name': 'colonel', 'age': 72, 'group': 'ateam' },
    { 'name': 'murdock', 'age': 68, 'group': 'ateam' },
    
    { 'name': 'grendel', 'age': 223, 'group': 'legend' }
];


var app = angular.module( 'sandboxApp', [] )
.factory( 'myFactory', [function() {
    var data_store = { 
        'data_key': external_data,
        'data_key_2': [ { 'name': 'foo', 'age': 33 }, { 'name': 'bar', 'age': 34 } ]
    };
    return {
        getData: function( key ) { return data_store[key]; }
    };
}])
.filter( 'offset', function() {
    return function( input, start ) {
        start = parseInt( start, 10 );
        return input.slice( start );
   ...