JSFiddle - React, Tailwind, and code Playground

by ckissi

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Code Editor</title>
    <link rel="stylesheet" href="/style.css" />
  </head>
  <body>
    <div class="toolbar">
      <button id="toggle-layout" class="toolbar-btn">
        Toggle Layout
      </button>
    </div>
    <div class="editor" data-layout="split">
      <div class="left-pane">
        <div class="pane" id="html-pane">
          <div class="pane-header">HTML</div>
          <textarea id="html-editor" spellcheck="false"></textarea>
        </div>
        <div class="resizer" data-direction="vertical"></div>
        <div class="pane" id="css-pane">
          <div class="pane-header">CSS</div>
          <textarea id="css-editor" spellcheck="false"></textarea>
        </div>
        <div class="resizer" data-direction="vertical"></div>
        <div class="pane" id="js-pane">
          <div class="pane-header">JavaScript</div>
          <textarea id="js-editor" spellcheck="false"></textarea>
        </div>
      </div>
      <div class="resizer" data-direction="horizontal"></div>
      <div class="right-pane">
        <div class="pane preview-container">
          <div class="pane-header">
            Preview
            <button id="run-btn">Run</button>
          </div>
          <iframe id="preview-frame"></iframe>
        </div>
      </div>
    </div>
    <script type="module" src="/main.js"></script>
  </body>
</html>

CSS

:root {
  --header-height: 40px;
  --toolbar-height: 50px;
  --resizer-size: 4px;
  --header-bg: #1a1a1a;
  --pane-bg: #242424;
  --resizer-color: #444;
  --text-color: #fff;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  color: var(--text-color);
  background-color: var(--pane-bg);
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.toolbar {
  height: var(--toolbar-height);
  background: var(--header-bg);
  display: flex;
  align-items: center;
  padding: 0 1rem;
  border-bottom: 1px solid var(--resizer-color);
}

.toolbar-btn {
  padding: 6px 16px;
  background: #646cff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.9rem;
}

.toolbar-btn:hover {
  background: #747bff;
}

.editor {
  display: flex;
  flex: 1;
  gap: var(--resizer-size);
  padding: var(--resizer-size);
}

/* Grid Layout */
.editor[data-layout="grid"] {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: var(--resizer-size);
}

.editor[data-layout="grid"] #html-pane {
  grid-column: 1;
  grid-row: 1;
}

.editor[data-layout="grid"] #css-pane {
  grid-column: 1;
  grid-row: 2;
}

.editor[data-layout="grid"] #js-pane {
  grid-column: 1;
  grid-row: 3;
}

.editor[data-layout="grid"] .preview-container {
  grid-column: 2;
  grid-row: 1 / span 3;
}

/* Split Layout */
.editor[data-layout="split"] {
  flex-direction: row;
}

.editor[data-layout="split"] .editors-container {
  display: flex;
  flex-direction: column;
  gap: var(--resizer-size);
  width: 50%;
}

.editor[data-layout="split"] .preview-container {
  width: 50%;
}

.pane {
  background: var(--pane-bg);
  border-radius: 4px;
  overflow: hidden;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.pane-header {
  height: var(--header-height);
  background: var(--header-bg);
  padding: 0 1rem;
  display:...

JavaScript

// Layout management
function initializeLayout() {
  const editor = document.querySelector('.editor');
  const toggleBtn = document.getElementById('toggle-layout');
  const leftPane = document.querySelector('.left-pane');
  const rightPane = document.querySelector('.right-pane');
  const jsPane = document.getElementById('js-pane');
  
  toggleBtn.addEventListener('click', () => {
    const currentLayout = editor.dataset.layout;
    const newLayout = currentLayout === 'split' ? 'split2' : 'split';
    editor.dataset.layout = newLayout;
    
    if (newLayout === 'split2') {
      // Move JS pane to right side
      rightPane.insertBefore(jsPane, rightPane.firstChild);
    } else {
      // Move JS pane back to left side
      const cssPane = document.getElementById('css-pane');
      leftPane.insertBefore(jsPane, null);
    }
    
    // Reset flex styles when switching layouts
    const containers = document.querySelectorAll('.pane');
    containers.forEach(container => {
      container.style.flex = '1';
      container.style.width = '';
    });
  });
}

// Initialize resizable panes
function initializeResizers() {
  const resizers = document.querySelectorAll('.resizer');
  
  resizers.forEach(resizer => {
    resizer.addEventListener('mousedown', startResize);
  });
}

function startResize(e) {
  e.preventDefault();
  const resizer = e.target;
  const direction = resizer.dataset.direction;
  const isHorizontal = direction === 'horizontal';
  
  const prevSibling = resizer.previousElementSibling;
  const nextSibling = resizer.nextElementSibling;
  
  // Get initial dimensions
  const initialSize = isHorizontal 
    ? prevSibling.offsetWidth 
    : prevSibling.offsetHeight;
  const initialPos = isHorizontal ? e.clientX : e.clientY;
  
  // Add event listeners for resize
  document.addEventListener('mousemove', resize);
  document.addEventListener('mouseup', stopResize);
  
  function resize(e) {
    const currentPos = isHorizontal ? e.clientX : e.clientY;
   ...