JSFiddle - React, Tailwind, and code Playground

by Abdul Ahmad

HTML

<div class='editor-menu'>
  <div class='item add-container'>
    + Add container
  </div>
  <div class='item add-component'>
    + Add component
  </div>
  <div class='item'>
    <div>
      Border color:
    </div>
    <div class='colors'>
      <div class='color white item'>
        <div class='white'></div>
      </div>
      <div class='color green item'>
        <div class='green'></div>
      </div>
      <div class='color red item'>
        <div class='red'></div>
      </div>
      <div class='color blue item'>
        <div class='blue'></div>
      </div>
    </div>
  </div>
</div>
<div class='colors'>
  <div class='add-color white item'>
    <div class='white'></div>
  </div>
  <div class='add-color green item'>
    <div class='green'></div>
  </div>
  <div class='add-color red item'>
    <div class='red'></div>
  </div>
  <div class='add-color blue item'>
    <div class='blue'></div>
  </div>
</div>
<div class='playground-box'>
  <div class='playground editable nestable'></div>
</div>

CSS

html, body {
  height: 100%;
  margin: 0;
  font-family: sans-serif;
  font-size: 14px;
}
.editor-menu {
  position: fixed;
  top: 10px;
  left: 10px;
  background-color: white;
  border: 1px solid #ddd;
  max-width: 150px;
}
.editor-menu > .item {
  padding: 5px 10px;
  border-bottom: 1px solid #ddd;
  color: #666;
}
.editor-menu .item:hover {
  cursor: pointer;
  color: black;
}
.editor-menu .item:last-of-type {
  border-bottom: none;
}
.playground-box {
  text-align: center;
  height: 100%;
}
.playground {
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border: 1px solid #ccc;
  min-width: 300px;
  width: 95%;
  min-height: 100px;
}
.container-box {
  width: 100%;
  text-align: center;
}
.container {
  display: inline-block;
  width: 90%;
  height: 40px;
  border: 1px dashed #ddd;
}
.container .designable {
  width: 100%;
  height: 100%;
}
.component {
  display: inline-block;
  border: 1px dashed #ccc;
  margin: 10px;
}
.component .designable {
  width: 40px;
  height: 40px;
}

.editing {
  border: 1px solid #00FF00;
  border-color: #82E882;
  border: 1px dashed red;
}
.red {
  background-color: red;
}
.blue {
  background-color: blue;
}
.green {
  background-color: green;
}
.white {
  background-color: white;
}
.colors {
  text-align: center;
}
.colors > .item {
  display: inline-block;
  margin: 3px;
  border-radius: 100%;
  width: 20px;
  height: 20px;
  opacity: 0.7;
}
.colors .item:hover {
  cursor: pointer;
  opacity: 1;
}

JavaScript

var editingElement = null;
var clickTimeStamp = null;
var editingClass = 'editing';
var playground = $('.playground');
var availableColors = [
	'white',
	'green',
  'red',
  'blue',
];

$(function() {
	$('.playground-box').on('click', '.editable', function(event) {
  	handleOnlyFirstClick(event.timeStamp, this);
  });
  $('.playground-box').on('dblclick', '.editable', function() {
    editingElement = null;
  	removeClassIfExists($(this), editingClass);
  });
  $('.add-container').on('click', function() {
  	$(playground).append(getContainer());
  });
  $('.add-component').on('click', function() {
  	if(nestable(editingElement)) {
    	$(editingElement).append(getComponent());
    } else if(editingElement === null) {
    	$(playground).append(getComponent());
    }
  });
  $('.add-color').on('click', function() {
  	if(editingElement !== null) {
    	console.log($(this).children().first().attr('class'));
      removeColorClassesIfExist(
      	getDesignableElement(editingElement)
      );
    	addClassIfNotExists(
        getDesignableElement(editingElement), 
        $(this).children().first().attr('class')
      );
    }
  });
});
function handleOnlyFirstClick(timeStamp, element) {
	if(clickTimeStamp === null) {
    clickTimeStamp = timeStamp;
    nullifyEditingElement();
    assignNewEditingElement(element);
    setTimeout(function() {
      clickTimeStamp = null;
    }, 100);
  }
}
function nullifyEditingElement() {
	if(editingElement !== null) {
    removeClassIfExists($(editingElement), editingClass);
    editingElement = null;
  }
}
function assignNewEditingElement(element) {
	editingElement = $(element);
  addClassIfNotExists($(element), editingClass);
}
function addClassIfNotExists(element, klass) {
	if(!$(element).hasClass(klass)) {
    $(element).addClass(klass);
  }
}
function removeClassIfExists(element, klass) {
	if($(element).hasClass(klass)) {
    $(element).removeClass(klass);
  }
}
function removeClassesIfExist(element, classes) {
	for(var i =...