JSFiddle - React, Tailwind, and code Playground

by levchenko_d

HTML

<div class="row main-row">
  <div class="column column-side tools-column">
    
    <div class="tools-list-wrapper">
      <ul class="tools-list">
        <li class="tools-list-item" data-tool-tag="select">S</li>
        <hr>
        <li class="tools-list-item" data-tool-tag="add_row">row</li>
        <li class="tools-list-item" data-tool-tag="add_button">button</li>
        <li class="tools-list-item"  data-tool-tag="add_img">img</li>
      </ul>
    </div>
  </div>
  <div class="column column-main canvas-column ">
    <iframe class="canvas-content"></iframe>
    <div class="selection-box-helper">
      <div class="top"></div>
      <div class="bottom"></div>
      <div class="left"></div>
      <div class="right"></div>
    </div>
  </div>
  <div class="column column-side properties-column "></div>
</div>

CSS

*{
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

body{
  margin: 0;
  overflow: hidden;
}


.row{
  display: flex;
}

.canvas-column{
  background: #fefefe;
  height: 100vh;
  width: calc(100% - 200px);
}

.tools-column,
.properties-column{
  background: #fafafa;
  width: 100px;
}

.tools-column{
  border-right: solid 1px #e2e2e2;
}

.properties-column{
  border-left: solid 1px #e2e2e2;
}

.tools-list{
  margin: 0;
  padding: 0;
}

.tools-list-item{
  display: block;
  list-style-type: none;
  text-align: center;
  padding: 10px;
}

.tools-list-item.selected{
  background: silver;
}

.canvas-column{
  position: relative;
  overflow: auto;
}

.canvas-content{
  width: 100%;
  height: 100vh;
  border: none;
}

.selection-box-helper.active *{
  position: absolute;
}

.selection-box-helper.active .top{
  border-top: solid 1px red;
}
.selection-box-helper.active .bottom{
  border-bottom: solid 1px red;
}
.selection-box-helper.active .left{
  border-left: solid 1px red;
}
.selection-box-helper.active .right{
  border-right: solid 1px red;
}

JavaScript

var items = document.querySelectorAll('.tools-list-item'),
		styles = '';

function selectDefaultTool(){
	var item = document.querySelector('.tools-list-item[data-tool-tag="select"]');
	selectItem(item);
}

function deselectItem(){
	var item = document.querySelector('.tools-list-item.selected');
  if(item){
  	item.className = item.className.replace('selected','').trim();
  }
	selectedTool = null;
}

function selectItem(item){
	if(item.className.indexOf('selected') > -1){
  	deselectItem();
  } else {
  	deselectItem();
    item.className += ' selected';
    selectedTool = item.getAttribute('data-tool-tag');
  }
}

function addClickListener(item){
	item.addEventListener('click', function(){
  	selectItem(item);
  });
}

for(var i=0; i<items.length; i++){
	addClickListener(items[i]);
}

var selectedTool = null;


//left side labels
var tools = [];

var Elements = {};

Elements.list = [];
Elements.addElement = function(options){
	Elements.list.push(options.toolTag);
  Elements[options.toolTag] = {
  	layout: options.layout,
    scripts: options.scripts,
    name: options.name
  }
  
  if(options.isTool){
  	tools.push(options.toolTag);
  }
  
  styles += options.style ? ' ' + options.style : '';
};


//Add row

Elements.addElement({
	name: 'row',
	layout: '<div class="row"></div>',
	acceptContent: true,
  isTool: true,
  toolTag: 'add_row',
  style: '.row{ display: block; width: calc(100% - 20px); min-height: 100px; margin: 10px; background: rgba(0,0,0,0.2); } .row:before, .row:after{ content: ""; clear: both; }',
	scripts: ''
});

Elements.addElement({
	name: 'button',
	layout: '<button class="button">I\'ma button!</button>',
	acceptContent: true,
  isTool: true,
  toolTag: 'add_button',
	scripts: ''
});

Elements.addElement({
	name: 'img',
	layout: '<img class="image" src="https://beat.today/images/covers/production/1_800.png" alt="">',
	acceptContent: false,
  isTool: true,
  toolTag: 'add_img',
  style: 'img{ max-width: 100%; }',
	scripts:...