JSFiddle - React, Tailwind, and code Playground

by Alain Dumesny

HTML

<!DOCTYPE html>
<html>

  <head>
    <meta charset="UTF-8">
    <title>title</title>

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/gridstack.min.css" />
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" />
    
    <link rel="stylesheet" href="https://maxcdn.icons8.com/fonts/line-awesome/1.1/css/line-awesome-font-awesome.min.css">

     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gridstack.all.js"></script>

  </head>

<!-- BODY -->
  <body>
    <div class="menu">
      <div class="controls">
        <div class="pro-button">Save</div>
        <div class="pro-button">Load</div>
        <div class="pro-button">Share</div>
      </div>
      <div class="share-box">
      as
      </div>
      <div class="widget-toolbox">
        <div class="pro-button widget-button" data-widget-id="1" data-widget-name="One" data-widget-min-width="1" data-widget-min-height="1" data-widget-max-width="2" data-widget-max-height="2">Widget 1</div>
        <div class="pro-button widget-button" data-widget-id="1" data-widget-name="Two" data-widget-min-width="3" data-widget-min-height="3" data-widget-max-width="4" data-widget-max-height="4">Widget 2</div>
        <div class="pro-button widget-button" data-widget-id="1" data-widget-name="Three">Widget 3</div>
      </div>
      <div id="widget-spawnbox" class="grid-stack">
        <div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="2">
          <div class="drag grid-stack-item-content"></div>
        </div>
      </div>
    </div>

    <div id = 'widget-designer' class="grid-stack">
      <div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="2">
        <div class="drag grid-stack-item-content"></div>
      </div>
      <div class="grid-stack-item" data-gs-x="4"...

CSS

body {
    font-family: Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, sans-serif;
    font-size: 14pt;
}

* {
    box-sizing: border-box;
}

.menu {
  display: flex;
  width: 100%;
  border: 1px black solid;
  border-radius: 2px;
  margin-bottom: 10px;
  padding: 2px;
}

.share-box {
  width: 200px;
  height: 50px;
  overflow-y: scroll;
  border: 1px gray solid;
  margin: 2px;
}

#widget-spawnbox {
  display: block;
  width: 400px;
  height: 100%;
}

.pro-button {
  display: inline-block;
  text-align: center;
  color: white;
  background-color: #3c7ee8;
  user-select: none;
  padding: 10px;
  border-radius: 5px;
  font-weight: bold;
  min-width: 20px;
  min-height: 20px;
}

.pro-button:hover {
  background-color: #26539b;
  cursor: pointer;
}


.grid-stack {
  border: 1px black solid;
}

.grid-stack-item-content {
  background: #ddd;
  margin: 10px;
  border: 1px gray solid;
}

JavaScript

class WidgetDashboardDesigner {
	constructor(id) {
    let cols = 12;
    let rows = 24;
    let vmargin = 5;
    let options = {
      width: cols,
      disableOneColumn: true,
      height: rows,
      animate: true, //allow tile slide animation
      float: true, //false if you want table to auto rearrange after moving/ resizing tiles 
      cellHeight: 'auto',
      cellHeightUnit: 'px',
      verticalMargin: vmargin, //spacing
      acceptWidgets: '.grid-stack-item', //true accepts widgets from other grids
      resizable: {
        handles: 'e, se, s, sw, w, nw, n, ne'
      }, //allow resizing from left, right, and bottom
    };

		// Initialize gridstack
    $(id).gridstack(options);
    this.gridObj = $(id).data('gridstack');
  }
  
  addWidget(elementId, x, y, w, h) {
    w = w ? w : 2;
    h = h ? h : 2;
    x = x ? x : 0;
    y = y ? y : 0;
    
    let widgetTemplate = `<div class="grid-stack-item"><div class="grid-stack-item-content">${elementId}</div></div>`;
    let tile = $(widgetTemplate);
    
    this.gridObj.addWidget(tile, x, y, false, w, null, h, null, elementId);
  }
}

class WidgetPlaceholderSpawnBox {
	constructor(id) {
  	let cols = 12;
    let rows = 6;
    let vmargin = 5;
    let options = {
      width: cols,
      disableOneColumn: true,
      height: rows,
      animate: true, //allow tile slide animation
      float: false,
      verticalMargin: vmargin, //spacing
      minWidth: 10,
      acceptWidgets: '.grid-stack-item', //true accepts widgets from other grids
    };
    
		// Initialize gridstack
    $(id).gridstack(options);
    this.gridObj = $(id).data('gridstack');
  }
  
  addWidget(id, name, x, y, w, h, minW, minH, maxW, maxH) {
    w = w ? w : 1;
    h = h ? h : 1;
    x = x ? x : 0;
    y = y ? y : 0;
    minW = minW ? minW : 1;
    minH = minH ? minH : 1;
    maxW = maxW ? maxW : null;
    maxH = maxH ? maxH : null;
    
    let widgetTemplate = `<div class="grid-stack-item"><div...