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:...