JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Compiler</title>
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" />
	<link rel="stylesheet" data-name="vs/editor/editor.main"
		href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.min.css">
	<link rel="stylesheet" href="style.css">
</head>

<body>
	<header id="head"><span id="name">Compiler</span>
		<div id="editorSettings">
			<button id="settings"><i class="fa-solid fa-gear"></i></button>
		</div>
	</header>
	<nav id="nav">
		<div class="tab-container" id="tabs">
		</div>
		<div id="newFile" popover>
			<button class="option" popovertarget="newFile" onclick="createNewFile('html')">New HTML file</button>
			<button class="option" popovertarget="newFile" onclick="createNewFile('css')">New CSS file</button>
			<button class="option" popovertarget="newFile" onclick="createNewFile('js')">New JS file</button>
		</div>
		<div id="stuff">
			<button popovertarget="newFile" id="fileCreator">+</button>
			<button id="run" onclick="previewFirstHtmlFile()">RUN</button>
		</div>
	</nav>
	<div id="main">
		<div id="input"></div>
		<div id="helper"></div>
		<div id="divider"></div>
		<div id="browser">
			<div id="output">
				<iframe id="outputFrame"></iframe>
			</div>
			<div id="console">
				<div id="verticalDivider"></div>
				<div id="verticalHelper"></div>
			</div>
		</div>
	</div>
	<script src="resize.js"></script>
	<script src="core.js"></script>
	<script src="editor.js"></script>
	<script src="file-actions.js"></script>
	<script src="preview.js"></script>
	<script src="console.js"></script>
</body>

</html>

CSS

:root {
  --inWidth: 50%;
  --outWidth: calc(100% - var(--inWidth));
  --height: calc(100% - 12px);
  --consoleHeight: calc(100% - var(--height));
  --console-bg: #1e1e1e;
  --console-text: #eaeaea;
  --log-color-log: #ccc;
  --log-color-info: #00f;
  --log-color-warn: #ff0;
  --log-color-error: #f00;
}

.custom-console {
  display: flex;
  flex-direction: column;
  border: 1px solid #555;
  overflow: hidden;
}

.console-controls {
  display: flex;
  gap: 5px;
  padding: 5px;
  background: #2b2b2b;
  border-bottom: 1px solid #444;
}

.console-controls button {
  background: #444;
  color: white;
  border: none;
  padding: 5px 10px;
  cursor: pointer;
  font-family: inherit;
}

.console-output {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  background: var(--console-bg);
}

.log-entry {
  padding: 5px 0;
  border-bottom: 1px solid #333;
  word-wrap: break-word;
}

.log-entry.log { color: var(--log-color-log); }
.log-entry.info { color: var(--log-color-info); }
.log-entry.warn { color: var(--log-color-warn); }
.log-entry.error { color: var(--log-color-error); }

.timestamp {
  color: #888;
  margin-right: 5px;
}

body {
  overflow: hidden;
  margin: 0;
}

#helper,
#verticalHelper {
  transform: translate(-50%, -50%);
  position: fixed;
  height: 400px;
  width: 400px;
  top: -1000px;
  z-index: 2147483647;
  /* backdrop-filter: invert(); */
}

#helper {
  cursor: ew-resize;
}

#verticalHelper {
  cursor: ns-resize;
}

#head {
  border-bottom: 1px #131419 solid;
  background-color: #1E2028;
  width: 100vw;
  height: 40px;
  display: flex;
  place-content: center;
}

#name {
  font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
  position: absolute;
  left: 0;
  font-size: 35px;
  color: #ffffff;
}

#nav {
  background-color: #161A22;
  /* Vertically align items in the nav */
  align-items: center;
  /* Ensure tabs are in a row */
  display: flex;
  width: 100vw;
  height: 40px;
}

#nav #stuff {
  justify-content: center;
  position:...

JavaScript

const helper = document.getElementById('helper');
let horizontalMouseDown = false;
let verticalMouseDown = false
const root = document.documentElement;
const resize = document.getElementById('divider');
const verticalDivider = document.getElementById('verticalDivider')
const verticalHelper = document.getElementById('verticalHelper')
const browser = document.getElementById('browser')

verticalDivider.addEventListener('mousedown', (e) => {
  verticalMouseDown = true;
  verticalHelper.style.left = `${e.clientX}px`;
  verticalHelper.style.top = `${e.clientY}px`;
})

resize.addEventListener('mousedown', (e) => {
  horizontalMouseDown = true;
  helper.style.left = `${e.clientX}px`;
  helper.style.top = `${e.clientY}px`;
});

document.addEventListener('mousemove', (e) => {
  if (horizontalMouseDown) {
    e.preventDefault();
    helper.style.left = `${e.clientX}px`;
    helper.style.top = `${e.clientY}px`;
    const viewportWidth = window.innerWidth;
    root.style.setProperty('--inWidth', `${e.clientX / viewportWidth * 100}%`);
  }
  if (verticalMouseDown) {
    e.preventDefault();
    verticalHelper.style.left = `${e.clientX}px`;
    verticalHelper.style.top = `${e.clientY}px`;
    const viewportHeight = browser.clientHeight;
    root.style.setProperty('--height', `clamp(0px, calc(${e.clientY} / ${viewportHeight} * 100% - 87px), calc(100% - 12px)`);
  }
});

document.addEventListener('mouseup', () => {
  horizontalMouseDown = false;
  verticalMouseDown = false;
  helper.style.left = `-2000px`;
  helper.style.top = `-2000px`;
  verticalHelper.style.left = `-2000px`;
  verticalHelper.style.top = `-2000px`;
});

const tabsDiv = document.getElementById('tabs');
const outputDiv = document.getElementById('output');
const inputDiv = document.getElementById('input');

let files = {};
let fileCounter = 0;
let activeFile = null;
let firstHtmlFileId = null;

class File {
  constructor(type, name, uniqueId) {
    this.uniqueId = uniqueId;
    this.name = name;
    this.type =...