JSFiddle - React, Tailwind, and code Playground

by Jesse M

HTML

<script src="https://jessemorgan.me/html2canvas/html2canvas.js"></script>
<link href="https://fonts.googleapis.com/css?family=Mali|Roboto&display=swap" rel="stylesheet">

<div class="one-third">
	<label>First box text<br />
		<input type="text" data-element="elem2" value="" placeholder="Enter custom text" />
	</label>
</div>
<div class="one-third">
	<label>Second box text<br />
		<input type="text" data-element="elem1" value="" placeholder="Enter custom text" />
	</label>
</div>
<div class="one-third">
	<label class="rotate">Rotate</label><br />
		<!-- button class="left">&olarr;</button -->
		<button class="right">&orarr; 45&deg;</button> OR <input class="degrees" type="number" max="359" min="0" value="0" />
</div>
<div class="one-third">
	<label>Font<br />
		<select id="font">
			<option value="Roboto">Roboto</option>
			<option value="Helvetica">Helvetica</option>
			<option value="Mali">Mali</option>
		</select>
	</label>
</div>
<div class="one-third">
	<label>Font size<br />
		<select id="font-size">
			<option value="10px">10px</option>
			<option value="11px">11px</option>
			<option value="12px">12px</option>
			<option value="13px">13px</option>
			<option value="14px">14px</option>
			<option value="15px">15px</option>
			<option value="16px">16px</option>
		</select>
	</label>
</div>
<div class="one-third">
	<label>Alignment<br />
		<select id="align">
			<option value="left">Left</option>
			<option value="right">Right</option>
			<option value="center">Center</option>
		</select>
	</label>
</div>
<div class="one-third">
	<label>Opacity<br />
		<input id="opacity" type="number" min="1" max="100" value="100" />
	</label>
</div>
<div class="one-third">
	<label>Letter Spacing<br />
		<input id="letter-spacing" type="number" min="0" max="100" value="0" />
	</label>
</div>
<div class="one-third">
	<label>Choose an image for the green box<br />
		<input id="image" type="file" />
	</label>
</div>

<div class="message-container">
	<p...

CSS

body {
	font-family: 'Roboto', sans-serif;
}

.one-third {
	width: 33%;
	display: inline-block;
	margin: 0;
	padding: 0;
}

label {
	display: inline-block;
	padding: 5px;
}

#container {
	position: relative;
	background-color: blue;
	margin: 10px auto;
}

#container > div {
	position: absolute;
	cursor: move;
	-webkit-user-select: none;
	-moz-user-select: none;
	-o-user-select: none;
	-ms-user-select: none;
	-khtml-user-select: none;
	user-select: none;
	transition: outline 0.2s ease-in-out, opacity 0.2s ease-in-out;
}

#elem1 {
	background-color: green;
	z-index: 1;
	background-size: contain !important;
}

#gripY, #gripX {
	position: absolute;
	text-align: center;
}

#gripY {
	top: -10px;
	left: calc(50% - 10px);
	cursor: ns-resize;
}
#gripX {
	left: -10px;
	top: calc(50% - 10px);
	cursor: ew-resize;
}

#elem2 {
	background: rgba(255, 0, 0, 0.75);
	z-index: 2;
}

#image-container {
	z-index: 3;
	background: rgba(255, 255, 255, 0.3);
}

.selected {
	outline: 3px solid #fff;
}

.layer button {
	display: none;
	position: absolute;
	bottom: 0;
	outline: none;
	border: none;
	width: 20px;
	height: 20px;
	cursor: pointer;
	transition: width 0.1s ease-in-out, height 0.1s ease-in-out;
}

.backward {
	left: 0;
	border-radius: 0 5px 0 0;
}

.forward {
	right: 0;
	border-radius: 5px 0 0 0;
}

.backward:hover, .forward:hover {
	width: 28px;
	height: 28px;
}

.message-container {
	min-height: 30px;
}

.message {
	display: none;
	color: #000;
}

JavaScript

$('#container > div').mousedown(function(){
	$('#container div').removeClass('selected');
	$('label:not(.rotate)').css('background', 'none');
	var id = $(this).attr('id');
	$(this).addClass('selected');
	$('[data-element="' + id + '"]').closest('label').css('background', '#4d4d4d');
	$('#font').val($(this).find('p').css('font-family'));
	$('.degrees').val(parseInt(getRotationDegrees($(this))));
	$('#letter-spacing').val($(this).find('p').css('letter-spacing').replace('px', ''));
	$('#font-size').val($(this).find('p').css('font-size'));
});


$('input[type="text"]').on('keyup', function(){
	$('#' + $(this).data('element') + ' > p').text($(this).val());
});


$('.layer').hover(function(){
	$(this).find('button').fadeIn();
}, function(){
	$(this).find('button').delay(300).fadeOut();
});

function getRotationDegrees(obj) {
    var matrix = obj.css('transform');
    if(matrix !== 'none') {
        var values = matrix.split('(')[1].split(')')[0].split(',');
        var a = values[0];
        var b = values[1];
        var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
    } else { var angle = 0; }
    return (angle < 0) ? angle + 360 : angle;
}


$('.right').click(function(){
	var degrees = parseInt(getRotationDegrees($('#container').find('.selected')));
	if(degrees === 360){
		degrees = 0;
	}
	degrees = degrees + 45;
	$('#container').find('.selected').css('transform', 'rotate(' + degrees + 'deg)');
	$('.degrees').val(degrees);
});

$('.degrees').on('change keyup', function(){
	$('#container').find('.selected').css('transform', 'rotate(' + $(this).val() + 'deg)');
});


$('.forward').click(function(e){
	e.preventDefault();
	var currentLayer = parseInt($(this).closest('div').css('z-index'));
	if(currentLayer === 5){
		$('.message').text('the element is at the highest layer').fadeIn(function(){
			$(this).delay(1500).fadeOut(function(){
				$(this).empty();
			});
		});	
	}else{
		$(this).closest('div').css('z-index', currentLayer +...