JSFiddle - React, Tailwind, and code Playground

by lain8dono

HTML

<script src="https://cdn.rawgit.com/yyx990803/vue/master/dist/vue.min.js"></script>
<!-- component template -->
<script type="text/x-template" id="grid-template">
  <table>
    <thead>
      <tr>
        <th v-repeat="key: columns"
          v-on="click:sortBy(key)"
          v-class="active: sortKey == key">
          {{key | capitalize}}
          <span class="arrow"
            v-class="reversed[key] ? 'dsc' : 'asc'">
          </span>
        </th>
          <th>
              remove
          </th>
      </tr>
    </thead>
    <tbody>
      <tr v-repeat="
        entry: data
        | filterBy filterKey
        | orderBy sortKey reversed[sortKey]">
        <td v-repeat="key: columns">
          {{entry[key]}}
        </td>
            <td>
                <input type="button" value="x" v-on="click: data.shift($value)"/>
            </td>
      </tr>
    </tbody>
  </table>
</script>

<!-- demo root element -->
<div id="demo">
  <form id="search">
    Search <input name="query" v-model="searchQuery">
  </form>
  <demo-grid v-with="
    data      : gridData,
    columns   : gridColumns,
    filterKey : searchQuery
  "></demo-grid>

      <input v-model="addName"/> 
      <input v-model="addPower"/>
      <input type="button" v-on="click:add" value="add"/>
</div>

CSS

body {
    font-family: Helvetica Neue, Arial, sans-serif;
    font-size: 14px;
    color: #444;
}
table {
    border: 2px solid #42b983;
    border-radius: 3px;
    background-color: #fff;
}
th {
    background-color: #42b983;
    color: rgba(255, 255, 255, 0.66);
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -user-select: none;
}
td {
    background-color: #f9f9f9;
}
th, td {
    min-width: 120px;
    padding: 10px 20px;
}
th.active {
    color: #fff;
}
th.active .arrow {
    opacity: 1;
}
.arrow {
    display: inline-block;
    vertical-align: middle;
    width: 0;
    height: 0;
    margin-left: 5px;
    opacity: 0.66;
}
.arrow.asc {
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-bottom: 4px solid #fff;
}
.arrow.dsc {
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 4px solid #fff;
}

JavaScript

// register the grid component
Vue.component('demo-grid', {
    template: '#grid-template',
    replace: true,
    data: function () {
        return {
            columns: null,
            sortKey: '',
            filterKey: '',
            reversed: {}
        }
    },
    compiled: function () {
        // initialize reverse state
        var self = this
        this.columns.forEach(function (key) {
            self.reversed.$add(key, false)
        })
    },
    methods: {
        sortBy: function (key) {
            this.sortKey = key
            this.reversed[key] = !this.reversed[key]
        },
    }
})

// bootstrap the demo
var demo = new Vue({
    el: '#demo',
    data: {
        search: '',
        gridColumns: ['name', 'power'],
        addName: '',
        addPower: 0,
        gridData: [{
            name: 'Chuck Norris',
            power: Infinity
        }, {
            name: 'Bruce Lee',
            power: 9000
        }, {
            name: 'Jacky Chang',
            power: 7000
        }, {
            name: 'Jet Li',
            power: 8000
        }]
    },
    methods: {
        add: function () {
            this.gridData.push({
                name: this.addName,
                power: this.addPower
            });
            this.addName = '';
            this.addPower = 0;
        }
    }
})