Skip to content

Instantly share code, notes, and snippets.

@simonw
Created April 30, 2025 03:13
Show Gist options
  • Save simonw/54f040ae2f2ca3b83cdc1b2e691936ab to your computer and use it in GitHub Desktop.
Save simonw/54f040ae2f2ca3b83cdc1b2e691936ab to your computer and use it in GitHub Desktop.

2025-04-30T03:07:24 conversation: 01jt2amck66mr54vbhcnkve6qs id: 01jt2amckb9spggb4m21691z3w

Model: mlx-community/Qwen3-8B-4bit

Prompt

what does this application do?

Prompt fragments

db8cc4537e78aef2e7f6332d7e73a86157fbeaba06d45bcab99b6472d64defa6
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML Live Preview</title>
  <style>
  * {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
    height: 100vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .container {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 60px);
    width: 100%;
  }

  .editor-container, .preview-container {
    flex: 1;
    overflow: hidden;
    position: relative;
  }

  .editor {
    width: 100%;
    height: 100%;
    resize: none;
    padding: 10px;
    border: none;
    border-bottom: 1px solid #ccc;
    font-size: 16px;
    font-family: monospace;
    background-color: #def;
  }

  .preview {
    width: 100%;
    height: 100%;
    border: none;
    background-color: white;
    overflow: auto;
  }

  .navbar {
    height: auto;
    min-height: 75px;
    background-color: #2c3e50;
    display: flex;
    align-items: center;
    padding: 16px 24px;
    border-bottom: 1px solid #34495e;
  }

  .title {
    margin: 0;
    flex: 1;
    color: #ffffff;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  }

  .button-group {
    display: flex;
    gap: 10px;
  }

  .toggle-button, .copy-button {
    background-color: #3498db;
    color: white;
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.3px;
    transition: all 0.2s ease;
  }

  .toggle-button:hover, .copy-button:hover {
    opacity: 0.9;
  }

  .copy-button {
    background-color: #27ae60;
  }

  .copy-button:active, .toggle-button:active {
    transform: translateY(1px);
  }

  .copy-notification {
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    background-color: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 10px 20px;
    border-radius: 4px;
    font-size: 14px;
    opacity: 0;
    transition: opacity 0.3s;
    pointer-events: none;
  }

  .copy-notification.show {
    opacity: 1;
  }

  /* Media query for mobile devices */
  @media (min-width: 768px) {
    .container {
      flex-direction: row;
    }
    
    .editor-container, .preview-container {
      flex: 1;
    }
    
    .editor {
      border-bottom: none;
      border-right: 1px solid #ccc;
    }
    
    .toggle-button {
      display: none;
    }
  }

  @media (max-width: 767px) {
    .toggle-button {
      display: block;
    }
    
    .preview-container {
      display: none;
    }
    
    .editor-container {
      display: block;
    }
    
    .container.preview-mode .preview-container {
      display: block;
    }
    
    .container.preview-mode .editor-container {
      display: none;
    }

    .title {
      font-size: 1rem;
    }
  }
  </style>
<!-- inspired by https://htmledit.squarefree.com/ by Jesse Ruderman -->
</head>
<body>
  <div class="navbar">
    <h1 class="title">HTML Live Preview</h1>
    <div class="button-group">
      <button class="copy-button">Copy HTML</button>
      <button class="toggle-button">View Preview</button>
    </div>
  </div>
  
  <div class="container">
    <div class="editor-container">
      <textarea class="editor" spellcheck="false" autofocus></textarea>
    </div>
    
    <div class="preview-container">
      <iframe class="preview" sandbox="allow-scripts allow-same-origin"></iframe>
    </div>
  </div>

  <div class="copy-notification">HTML copied to clipboard!</div>

  <script type="module">
// Default content for the editor
const defaultContent = `<h3>Real-time HTML editor</h3>
<p>Enter HTML here and see a live preview as you type.</p>`;

// DOM elements
const editor = document.querySelector('.editor');
const preview = document.querySelector('.preview');
const toggleButton = document.querySelector('.toggle-button');
const copyButton = document.querySelector('.copy-button');
const copyNotification = document.querySelector('.copy-notification');
const container = document.querySelector('.container');

// Initialize editor with default content
editor.value = defaultContent;

// Create a blob URL for the iframe content
function createBlobURL(htmlContent) {
  const blob = new Blob([htmlContent], { type: 'text/html' });
  return URL.createObjectURL(blob);
}

// Update preview when editor content changes
function updatePreview() {
  try {
    // Create a new blob URL with the current HTML content
    const blobURL = createBlobURL(editor.value);
    
    // Set the iframe src to the new blob URL
    preview.src = blobURL;
    
    // Clean up the old blob URL when the iframe loads
    const oldURL = preview.dataset.blobURL;
    if (oldURL) {
      URL.revokeObjectURL(oldURL);
    }
    
    // Store the current blob URL for cleanup later
    preview.dataset.blobURL = blobURL;
  } catch (e) {
    console.error('Error updating preview:', e);
  }
}

// Copy HTML to clipboard
function copyToClipboard() {
  try {
    // Select the text
    editor.select();
    
    // Copy to clipboard
    navigator.clipboard.writeText(editor.value)
      .then(() => {
        // Show notification
        copyNotification.classList.add('show');
        
        // Hide notification after 2 seconds
        setTimeout(() => {
          copyNotification.classList.remove('show');
        }, 2000);
      })
      .catch(err => {
        console.error('Failed to copy text: ', err);
        // Fallback for older browsers
        document.execCommand('copy');
        copyNotification.classList.add('show');
        setTimeout(() => {
          copyNotification.classList.remove('show');
        }, 2000);
      });
      
    // Restore focus to editor
    setTimeout(() => {
      // Return to editing without interrupting workflow too much
      editor.focus();
    }, 50);
  } catch (err) {
    console.error('Failed to copy text: ', err);
  }
}

// Debounce function to prevent too many updates
function debounce(func, wait) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(() => func(), wait);
  };
}

// Debounced update function (updates after 300ms of inactivity)
const debouncedUpdate = debounce(updatePreview, 300);

// Set up event listeners for editor changes
editor.addEventListener('input', debouncedUpdate);

// Initialize the preview when page loads
window.addEventListener('load', updatePreview);

// Toggle between editor and preview on mobile
toggleButton.addEventListener('click', () => {
  const isPreviewMode = container.classList.toggle('preview-mode');
  toggleButton.textContent = isPreviewMode ? 'View Editor' : 'View Preview';
});

// Handle resize events to reapply styles
window.addEventListener('resize', () => {
  // Force iframe to refresh its contents after resize
  updatePreview();
});

// Add click event listener for copy button
copyButton.addEventListener('click', copyToClipboard);
  </script>
</body>
</html>

Response

<think>
Okay, let me try to figure out what this HTML application does. So, looking at the code, there's a textarea where you can type HTML, and there's an iframe that's supposed to preview the HTML. The title says "HTML Live Preview," so that's a hint.

First, the structure: there's a navbar with a title and buttons for "Copy HTML" and "View Preview." The main container has two parts: the editor-container with a textarea and the preview-container with an iframe. On larger screens, they split side by side, but on mobile, the preview is hidden, and the toggle button switches between editor and preview.

The JavaScript part is important. The default content is some HTML with a heading and paragraph. The script creates a blob URL from the editor's content and sets it as the iframe's src. That makes sense because iframes can't directly display the content of a textarea unless it's served via a URL. So, the blob URL allows the iframe to load the HTML as a local resource.

The updatePreview function is called whenever the editor's content changes. It creates a new blob URL each time, which is necessary because the old one needs to be revoked to free memory. The debounce function ensures that the preview updates aren't too frequent, which is efficient.

The copy button copies the editor's content to the clipboard. It uses navigator.clipboard.writeText, which is modern, but there's a fallback with document.execCommand('copy') for older browsers. The notification shows up when it's copied.

The toggle button switches between showing the editor and preview on mobile. On desktop, the layout is fixed, but on mobile, the preview is hidden, and clicking the button toggles it. The CSS media queries handle this behavior.

So putting it all together, this app allows users to write HTML in a textarea and see a live preview in an iframe. It also lets them copy the HTML code to the clipboard and switch between editor and preview views, especially on mobile devices. The live preview updates as the user types, making it a real-time editor with a preview feature.
</think>

This application is a live HTML editor with real-time preview and mobile-friendly interface. Here's a breakdown of its functionality:


Core Features

  1. Live HTML Editor

    • A textarea allows users to input/modify HTML code.
    • Changes are immediately reflected in a preview iframe (HTML rendered as a webpage).
  2. Live Preview

    • The iframe dynamically loads the HTML from the editor using a blob URL (a temporary URL for in-browser data).
    • The preview updates in real-time as the user types (via debounced updates to avoid lag).
  3. Copy to Clipboard

    • A "Copy HTML" button copies the editor's content to the clipboard.
    • Fallback support for older browsers using document.execCommand('copy').
  4. Responsive Design

    • Desktop: Side-by-side editor and preview.
    • Mobile: Toggles between editor and preview view using a button.
    • A "View Preview" button on desktop allows switching between views.

Technical Implementation

  • Blob URLs: Used to load HTML content into the iframe securely.
  • Debouncing: Prevents excessive iframe updates by delaying refreshes (300ms).
  • Memory Management: Old blob URLs are revoked to free memory.
  • Copy Notification: A floating message appears when HTML is copied to the clipboard.

Use Case

This tool is ideal for:

  • Web developers testing HTML snippets.
  • Learning HTML by seeing real-time rendering.
  • Mobile users who need to switch between editing and previewing.

Summary

The application provides a real-time HTML editor with preview, clipboard support, and responsive design for both desktop and mobile users. It’s a lightweight tool for quickly testing and visualizing HTML code.

Token usage:

1,861 input, 805 output

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment