<script src="../../dist/vue.global.js"></script>

<!-- DemoGrid component template -->
<script type="text/x-template" id="grid-template">
  <table v-if="filteredData.length">
    <thead>
      <tr>
        <th v-for="key in columns"
          @click="sortBy(key)"
          :class="{ active: state.sortKey == key }">
          {{ capitalize(key) }}
          <span class="arrow" :class="state.sortOrders[key] > 0 ? 'asc' : 'dsc'">
          </span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="entry in filteredData">
        <td v-for="key in columns">
          {{entry[key]}}
        </td>
      </tr>
    </tbody>
  </table>
  <p v-else>No matches found.</p>
</script>
<!-- DemoGrid component script -->
<script>
const { reactive, computed } = Vue

const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)

const DemoGrid = {
  template: '#grid-template',
  props: {
    data: Array,
    columns: Array,
    filterKey: String
  },
  setup(props) {
    const state = reactive({
      sortKey: '',
      sortOrders: props.columns.reduce((o, key) => (o[key] = 1, o), {})
    })

    const filteredData = computed(() => {
      let { data, filterKey } = props
      if (filterKey) {
        filterKey = filterKey.toLowerCase()
        data = data.filter(row => {
          return Object.keys(row).some(key => {
            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
          })
        })
      }
      const { sortKey } = state
      if (sortKey) {
        const order = state.sortOrders[sortKey]
        data = data.slice().sort((a, b) => {
          a = a[sortKey]
          b = b[sortKey]
          return (a === b ? 0 : a > b ? 1 : -1) * order
        })
      }
      return data
    })

    function sortBy(key) {
      state.sortKey = key
      state.sortOrders[key] *= -1
    }

    return {
      state,
      filteredData,
      sortBy,
      capitalize
    }
  }
}
</script>

<!-- App template (in DOM) -->
<div id="demo">
  <form id="search">
    Search <input name="query" v-model="searchQuery">
  </form>
  <demo-grid
    :data="gridData"
    :columns="gridColumns"
    :filter-key="searchQuery">
  </demo-grid>
</div>
<!-- App script -->
<script>
const App = {
  components: {
    DemoGrid
  },
  data: {
    searchQuery: '',
    gridColumns: ['name', 'power'],
    gridData: [
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ]
  }
}

Vue.createApp().mount(App, '#demo')
</script>

<style>
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;
  -ms-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;
}
</style>