JSFiddle - React, Tailwind, and code Playground

codemirror

by Travis Almand

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.38.0/codemirror.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/codemirror.css">
<div class="panel">
	<button id="build">build</button>
  <select id="tests">
    <option value="empty">empty</option>
    <option value="entry1">test1</option>
  </select>
  <select id="answers">
    <option value="empty">empty</option>
    <option value="entry1">answer1</option>
  </select>
	<button id="compare">compare</button>
</div>

<div class="grid">
  <div class="left">
    <div class="top content">
    	<textarea id="html_text"></textarea>
    </div>
    <div class="gutter" data-gutter="left"></div>
    <div class="bottom content">
    	<textarea id="css_text"></textarea>
    </div>
  </div>
  <div class="gutter" data-gutter="center"></div>
  <div class="right">
    <div class="top content">
      <div id="image_container"></div>
    </div>
    <div class="gutter" data-gutter="right"></div>
    <div class="bottom content">
    	<div id="html_container"></div>
    </div>
  </div>
</div>

<div id="compare_container"></div>

SCSS

:root {
  --left: 1fr;
  --topLeft: 1fr;
  --topRight: 1fr;
  --htmlContainerHeight: 100px;
  --htmlContainerWidth: 100px;
  --compareLeft: 0;
  --compareTop: 0;
  --compareHeight: 0;
  --compareWidth: 0;
  --compareBlend: difference;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
	position: relative;
}

.grid {
  display: grid;
  grid-template-columns: var(--left) 10px 1fr;
  height: 100%;
  
  .left {
    display: grid;
    grid-template-rows: var(--topLeft) 10px 1fr;
  }
  .right {
    display: grid;
    grid-template-rows: var(--topRight) 10px 1fr;
    
    .top,
    .bottom {
      display: flex;
    }
  }
  
  .gutter {
    background-color: gray;
    
    &[data-gutter="left"],
    &[data-gutter="right"] {
      cursor: ns-resize;
    }
    
    &[data-gutter="center"] {
      cursor: ew-resize;
    }
  }
  .content {
    background-color: gainsboro;
  }
}

.panel {
	background-color: black;
	display: flex;
	padding: 10px;
	
	button {
		background-color: #fff !important;
		border: 3px solid gainsboro !important;
		border-radius: 5px !important;
		color: black !important;
	}
	
	#compare {
		margin-left: auto;
	}
}

#html_container,
#image_container {
  background-color: #fff;
  border: 2px solid red;
  height: var(--htmlContainerHeight);
  margin: auto;
  transition: all 0.5s;
  width: var(--htmlContainerWidth);
}
#image_container {
  background-position: top left;
  background-repeat: no-repeat;
  background-size: 100%;
}

#compare_container {
  background-position: top left;
  background-repeat: no-repeat;
  background-size: 100%;
  height: var(--compareHeight);
  left: var(--compareLeft);
  mix-blend-mode: var(--compareBlend);
  position: absolute;
  top: var(--compareTop);
  width: var(--compareWidth);
  z-index: 100;
}

.CodeMirror {
	height: 100%;
}

.image1 {
  background-image:...

JavaScript

console.clear();

const leftGutter = document.querySelector('[data-gutter="left"]');
const centerGutter = document.querySelector('[data-gutter="center"]');
const rightGutter = document.querySelector('[data-gutter="right"]');
const gutter = {};
const buildBtn = document.querySelector('#build');
const compareBtn = document.querySelector('#compare');
const imageContainer = document.querySelector('#image_container');
const htmlContainer = document.querySelector('#html_container');
const compareContainer = document.querySelector('#compare_container');
const testSelect = document.querySelector('#tests');
const answerSelect = document.querySelector('#answers');
const entries = {
	'empty' : {
  	'html': '',
    'css': '',
    'container': {
    	'width': 100,
      'height': 100
    },
    'class': ''
  },
	'entry1' : {
  	'html': '<div class="container">\n\t<button class="btn">button</button>\n</div>',
    'css': '.container {\n\talign-items: center;\n\tdisplay: flex;\n\theight: 100%;\n\tjustify-content: center;\n}\n.btn {\n\tbackground-color: #fff;\n\tborder: 2px solid #000;\n\tborder-radius: 5px;\n\tpadding: 10px;\n}',
    'container': {
    	'width': 200,
      'height': 200
    },
    'class': 'image1'
  }
};

let draggingGutter = false;

leftGutter.addEventListener('mousedown', gutter_MD);
centerGutter.addEventListener('mousedown', gutter_MD);
rightGutter.addEventListener('mousedown', gutter_MD);
document.body.addEventListener('mouseup', body_MU);
document.body.addEventListener('mouseleave', body_MU);
document.body.addEventListener('mousemove', body_MM);
testSelect.addEventListener('change', changeTest);
answerSelect.addEventListener('change', changeAnswer);

function gutter_MD (e) {
  draggingGutter = true;
  gutter.x = e.clientX;
	gutter.y = e.clientY;
  gutter.type = e.target.dataset.gutter;
}

function body_MU (e) {
	draggingGutter = false;
}

function body_MM (e) {
	if (draggingGutter) {
  	var bodyHeight = document.body.clientHeight;
    var bodyWidth =...