JSFiddle - React, Tailwind, and code Playground

by samonela

HTML

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  <title>Datatables admin</title>
  <meta name="description" content="Datatables administration panel" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <link rel="stylesheet" href="styles.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
        integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous" />
  <link rel="stylesheet" href="https://cdn.datatables.net/1.10.18/css/jquery.dataTables.min.css" />
</head>

<body class="dta">
  <div id="datatables-admin">
    <h1>Datatables admin</h1>

    <table id="editor">
      <thead>
        <tr>
          <th v-for="(column, index_col) in columns" :key="index_col">
            <i class="fas fa-long-arrow-alt-left fa-2x dta-btn move-col-left" title="Move column to left" v-on:click="move_col_to_left(index_col)"></i>
            <i class="fas fa-long-arrow-alt-right fa-2x dta-btn move-col-right" title="Move column to right" v-on:click="move_col_to_right(index_col)"></i>
            <i class="fas fa-plus fa-2x dta-btn add-col" title="Add a column after this one" v-on:click="add_col(index_col + 1)"></i>
            <i class="fas fa-times fa-2x dta-btn delete-col" title="Delete this column" v-on:click="delete_col(index_col)"></i>
            <br />
            <editable :content="columns[index_col]" v-on:update="update_col($event, index_col)"></editable>
          </th>
          <th>
            <i class="fas fa-plus fa-2x dta-btn add-col" title="Add a column" v-on:click="add_col(0)"></i>
            <i class="fas fa-plus fa-2x dta-btn add-row" title="Add a row" v-on:click="add_row(0)"></i>
            <i class="fas fa-times fa-2x dta-btn delete-all-cols" title="Delete all columns" v-on:click="delete_all_cols"></i>
            <i class="fas fa-times fa-2x dta-btn...

CSS

/* https://coolors.co/96adc8-d7ffab-fcff6c-d89d6a-6d454c
   #96adc8 #d7ffab #fcff6c #d89d6a #6d454c
*/
@import url('https://fonts.googleapis.com/css?family=Open+Sans|Tangerine');

body.dta {
  font-family: 'Open Sans', sans-serif;
  background: #6d454c;
  color: #6d454c;
}

body.dta div#datatables-admin {
  background: #EEEEEE;
  padding: 20px;
  margin: 20px;
}

body.dta div#datatables-admin h1 {
  font-family: 'Tangerine', cursive;
  color: #d89d6a;
  text-align: center;
  font-size: 86px;
  font-weight: 500;
  margin: 20px;
}

body.dta div#datatables-admin table#editor {
  background: #CCCCCC;
  padding: 10px;
  border-spacing: 5px;
  color: #111111;
  margin: auto;
}

body.dta div#datatables-admin table#editor tr,
body.dta div#datatables-admin table#editor td,
body.dta div#datatables-admin table#editor th {
  background: #FFFFFF;
  padding: 5px;
  margin: 5px;
  text-align: center;
}

body.dta div#datatables-admin table#editor th {
  user-select: none;
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  -o-user-select: none;
}

body.dta div#datatables-admin .dta-btn {
  color: #96adc8;

  user-select: none;
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  -o-user-select: none;
}

body.dta div#datatables-admin .dta-btn:hover {
  color: #d89d6a;
  cursor: pointer;
}

body.dta div#datatables-admin div.table-preview-container {
  text-align: center;
  margin-top: 40px;
}

body.dta div#datatables-admin table.table-render-preview {
  margin: auto;
}

body.dta div#datatables-admin button.render-table {
  margin-bottom: 40px;
  padding: 10px;
}

JavaScript

Vue.component('editable', {
  template: `
    <div contenteditable="true" @blur="emitChange">
      {{ content }}
    </div>
  `,
  props: ['content'],
  methods: {
    emitChange(ev) {
      this.$emit('update', ev.target.textContent)
    }
  }
});

Vue.component('table-preview', {
  template: `
    <div ref="tablePreviewContainer" class="table-preview-container">
      <button class='render-table' v-on:click="render_table">Preview table</button>
      <table ref="tableRenderPreview" class="table-render-preview"></table>
    </div>
  `,
  props: ['content'],
  methods: {
    render_table(event) {
    //console.log('refs:', this.$refs);
      var columns = this.$parent.columns;
      var rows = this.$parent.rows;
      var el = event.srcElement;
      var parent = el.offsetParent;
      //var table_placeholder = document.querySelector('.table-render-preview');
      var table_placeholder = this.$refs.tableRenderPreview;//('.table-render-preview');


      function make_table_html(columns, rows) {
        function render_link(url) {
          if(url !== undefined) {
            return "<a href='" + url +"' target='_blank' title=" + url + ">Link<span style='display:none !important'>" + url + "</span></a>";
          } else {
            return "N/A";
          }
        }

        var result = "<table border=1><thead><tr>";

        for(var i = 0; i < columns.length; i++) {
          result += "<th>" + columns[i] + "</th>";
        }

        result += "</thead><tbody>"
        for(var i = 0; i < rows.length; i++) {
          result += "<tr>";
          for(var j = 0; j < rows[i].length; j++) {
            if(columns[j] == "URL") {
              result += "<td>" +  render_link(rows[i][j]) + "</td>";
            } else {
              result += "<td>" + rows[i][j] + "</td>";
            }
          }
          result += "</tr>";
        }
        result += "</tbody></table>";

        return result;
      }

      if...