use codemirror over prism

Hunter
Monday, July 7th, 2025 at 6:45 PM

index.html+64-57

index.html
  4      <meta charset="UTF-8">
  5      <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6      <title>HTML Laboratory</title>
  7 +    <script type="module">
  8 +        import {EditorView, keymap} from "https://esm.sh/@codemirror/view@6"
  9 +        import {EditorState} from "https://esm.sh/@codemirror/state@6"
 10 +        import {defaultKeymap} from "https://esm.sh/@codemirror/commands@6"
 11 +        import {html} from "https://esm.sh/@codemirror/lang-html@6"
 12 +        import {oneDark} from "https://esm.sh/@codemirror/theme-one-dark@6"
 13 +        
 14 +        window.CodeMirror = {EditorView, EditorState, keymap, defaultKeymap, html, oneDark};
 15 +    </script>
 16      <style>
 17          :root {
 18              --bg-color: #2d2d2d;

 54          #editor {
 55              width: 100%;
 56              height: 100%;
    -            border: none;
    -            outline: none;
 57              font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
 58              font-size: 21px;
    -            padding: 15px;
    -            overflow: auto;
 59 +        }
 60 +
 61 +        /* CodeMirror styling */
 62 +        .cm-editor {
 63 +            width: 100%;
 64 +            height: 100%;
 65              background: var(--editor-bg);
 66              color: var(--text-color);
    -            tab-size: 4;
    -            white-space: pre-wrap;
    -            overflow-x: auto;
    -            display: block;
 67 +        }
 68 +
 69 +        .cm-content {
 70 +            padding: 15px;
 71 +            font-size: 21px;
 72              line-height: 1.5;
 73          }
 74  
    -        #editor:empty:before {
    -            content: attr(data-placeholder);
    -            color: #666;
 75 +        .cm-focused {
 76 +            outline: none;
 77          }
 78  
 79          #preview {

113  </head>
114  <body>
115      <div class="editor-pane">
    -        <div id="editor" contenteditable="true" spellcheck="false" data-placeholder="Type your HTML, CSS, and JavaScript here..."></div>
116 +        <div id="editor"></div>
117      </div>
118      
119      <div class="preview-pane">
120          <iframe id="preview" sandbox="allow-scripts"></iframe>
121      </div>
122  
    -    <script>
123 +    <script type="module">
124          let updateTimer;
    -        const editor = document.getElementById('editor');
125 +        let editorView;
126          const preview = document.getElementById('preview');
127          const storageKey = 'html-lab-content';
128  
129          function updatePreview() {
    -            const code = editor.textContent;
130 +            const code = editorView.state.doc.toString();
131              const blob = new Blob([code], { type: 'text/html' });
132              const url = URL.createObjectURL(blob);
133              preview.src = url;

138  
139          function saveToStorage() {
140              try {
    -                // Save both the inner HTML (for whitespace preservation) and text content
    -                const data = {
    -                    html: editor.innerHTML,
    -                    text: editor.textContent
    -                };
    -                localStorage.setItem(storageKey, JSON.stringify(data));
141 +                const code = editorView.state.doc.toString();
142 +                localStorage.setItem(storageKey, code);
143              } catch (e) {
144                  // Handle localStorage errors silently
145                  console.warn('Could not save to localStorage:', e);

150              try {
151                  const saved = localStorage.getItem(storageKey);
152                  if (saved !== null) {
153 +                    // Handle old format that might be JSON
154                      try {
    -                        // Try to parse as JSON first (new format)
155                          const data = JSON.parse(saved);
    -                        if (data.html) {
    -                            editor.innerHTML = data.html;
    -                        } else if (data.text) {
    -                            editor.textContent = data.text;
    -                        }
156 +                        return data.text || data.html || saved;
157                      } catch (parseError) {
    -                        // Fallback to old format (plain text)
    -                        editor.textContent = saved;
158 +                        return saved;
159                      }
    -                    return true;
160                  }
161              } catch (e) {
162                  // Handle localStorage errors silently
163                  console.warn('Could not load from localStorage:', e);
164              }
    -            return false;
165 +            return '';
166          }
167  
    -
    -        // Handle Tab key to insert tab character
    -        editor.addEventListener('keydown', function(e) {
    -            if (e.key === 'Tab') {
    -                e.preventDefault();
    -                document.execCommand('insertText', false, '\t');
    -            }
    -        });
    -
    -        // Update preview after 0.5 seconds of no typing
    -        editor.addEventListener('input', function() {
    -            clearTimeout(updateTimer);
    -            updateTimer = setTimeout(updatePreview, 500);
    -            
    -            // Save to localStorage on every change
    -            saveToStorage();
    -        });
    -
168          // Save functionality with Cmd+S
169          document.addEventListener('keydown', function(e) {
170              if ((e.metaKey || e.ctrlKey) && e.key === 's') {

174          });
175  
176          function saveFile() {
    -            const code = editor.textContent;
177 +            const code = editorView.state.doc.toString();
178              const blob = new Blob([code], { type: 'text/html' });
179              const url = URL.createObjectURL(blob);
180              

186              URL.revokeObjectURL(url);
187          }
188  
    -        // Initialize the editor content and render
    -        function initialize() {
    -            // Always try to load from localStorage regardless of refresh type
    -            loadFromStorage();
189 +        // Wait for CodeMirror to be available
190 +        function initializeCodeMirror() {
191 +            if (!window.CodeMirror) {
192 +                setTimeout(initializeCodeMirror, 100);
193 +                return;
194 +            }
195 +
196 +            const {EditorView, EditorState, keymap, defaultKeymap, html, oneDark} = window.CodeMirror;
197              
    -            // Focus the editor
    -            editor.focus();
198 +            // Load saved content
199 +            const savedContent = loadFromStorage();
200              
201 +            // Create CodeMirror editor
202 +            editorView = new EditorView({
203 +                state: EditorState.create({
204 +                    doc: savedContent,
205 +                    extensions: [
206 +                        keymap.of(defaultKeymap),
207 +                        html(),
208 +                        oneDark,
209 +                        EditorView.updateListener.of((update) => {
210 +                            if (update.docChanged) {
211 +                                clearTimeout(updateTimer);
212 +                                updateTimer = setTimeout(updatePreview, 500);
213 +                                saveToStorage();
214 +                            }
215 +                        })
216 +                    ]
217 +                }),
218 +                parent: document.getElementById('editor')
219 +            });
220 +
221              // Initial render
222              updatePreview();
223          }
224  
225          // Initialize when page loads
    -        initialize();
226 +        initializeCodeMirror();
227      </script>
228  </body>
229  </html>