tabs over spaces
Hunter
Monday, July 7th, 2025 at 7:09 PM
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>HTML Laboratory</title>
- <script type="module">
- import {EditorView, keymap} from "https://esm.sh/@codemirror/view@6"
- import {EditorState} from "https://esm.sh/@codemirror/state@6"
- import {defaultKeymap, indentWithTab} from "https://esm.sh/@codemirror/commands@6"
- import {html} from "https://esm.sh/@codemirror/lang-html@6"
- import {githubDark} from "https://esm.sh/@fsegurai/codemirror-theme-github-dark"
-
- window.CodeMirror = {EditorView, EditorState, keymap, defaultKeymap, indentWithTab, html, githubDark};
- </script>
- <style>
- :root {
- --bg-color: #2d2d2d;
- --text-color: #f8f8f2;
- --editor-bg: #272822;
- --preview-bg: #2d2d2d;
- }
-
-
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
-
- body {
- font-family: monospace;
- background: var(--bg-color);
- color: var(--text-color);
- height: 100vh;
- display: flex;
- overflow: hidden;
- }
-
- .editor-pane {
- width: 50%;
- height: 100vh;
- background: var(--preview-bg);
- position: relative;
- }
-
- .preview-pane {
- width: 50%;
- height: 100vh;
- background: var(--preview-bg);
- position: relative;
- }
-
- #editor {
- width: 100%;
- height: 100%;
- font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
- font-size: 21px;
- }
-
- /* CodeMirror styling */
- .cm-editor {
- width: 100%;
- height: 100%;
- background: var(--editor-bg);
- color: var(--text-color);
- }
-
- .cm-content {
- padding: 15px;
- font-size: 21px;
- line-height: 1.5;
- }
-
- .cm-focused {
- outline: none;
- }
-
- #preview {
- width: 100%;
- height: 100%;
- border: none;
- background: white;
- overflow: auto;
- }
-
- #editor {
- padding-top: 15px;
- }
-
- #preview {
- padding-top: 0;
- }
-
- /* Hide scrollbars until needed */
- ::-webkit-scrollbar {
- width: 12px;
- }
-
- ::-webkit-scrollbar-track {
- background: var(--editor-bg);
- }
-
- ::-webkit-scrollbar-thumb {
- background: var(--border-color);
- border-radius: 6px;
- }
-
- ::-webkit-scrollbar-thumb:hover {
- background: var(--header-text);
- }
- </style>
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, indentWithTab} from "https://esm.sh/@codemirror/commands@6"
11 + import {html} from "https://esm.sh/@codemirror/lang-html@6"
12 + import {githubDark} from "https://esm.sh/@fsegurai/codemirror-theme-github-dark"
13 + import {indentUnit} from "https://esm.sh/@codemirror/language@6"
14 +
15 + window.CodeMirror = {EditorView, EditorState, keymap, defaultKeymap, indentWithTab, html, githubDark, indentUnit};
16 + </script>
17 + <style>
18 + :root {
19 + --bg-color: #2d2d2d;
20 + --text-color: #f8f8f2;
21 + --editor-bg: #272822;
22 + --preview-bg: #2d2d2d;
23 + }
24 +
25 +
26 + * {
27 + margin: 0;
28 + padding: 0;
29 + box-sizing: border-box;
30 + }
31 +
32 + body {
33 + font-family: monospace;
34 + background: var(--bg-color);
35 + color: var(--text-color);
36 + height: 100vh;
37 + display: flex;
38 + overflow: hidden;
39 + }
40 +
41 + .editor-pane {
42 + width: 50%;
43 + height: 100vh;
44 + background: var(--preview-bg);
45 + position: relative;
46 + }
47 +
48 + .preview-pane {
49 + width: 50%;
50 + height: 100vh;
51 + background: var(--preview-bg);
52 + position: relative;
53 + }
54 +
55 + #editor {
56 + width: 100%;
57 + height: 100%;
58 + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
59 + font-size: 21px;
60 + tab-size: 2;
61 + }
62 +
63 + /* CodeMirror styling */
64 + .cm-editor {
65 + width: 100%;
66 + height: 100%;
67 + background: var(--editor-bg);
68 + color: var(--text-color);
69 + tab-size: 2;
70 + }
71 +
72 + .cm-content {
73 + padding: 15px;
74 + font-size: 21px;
75 + line-height: 1.5;
76 + tab-size: 2;
77 + }
78 +
79 + .cm-focused {
80 + outline: none;
81 + }
82 +
83 + /* Force tab size to 2 spaces - override theme defaults */
84 + .cm-editor .cm-content,
85 + .cm-editor .cm-line,
86 + .cm-editor {
87 + tab-size: 2 !important;
88 + -moz-tab-size: 2 !important;
89 + }
90 +
91 + #preview {
92 + width: 100%;
93 + height: 100%;
94 + border: none;
95 + background: white;
96 + overflow: auto;
97 + }
98 +
99 + #preview {
100 + padding-top: 0;
101 + }
102 +
103 + /* Hide scrollbars until needed */
104 + ::-webkit-scrollbar {
105 + width: 12px;
106 + }
107 +
108 + ::-webkit-scrollbar-track {
109 + background: var(--editor-bg);
110 + }
111 +
112 + ::-webkit-scrollbar-thumb {
113 + background: var(--border-color);
114 + border-radius: 6px;
115 + }
116 +
117 + ::-webkit-scrollbar-thumb:hover {
118 + background: var(--header-text);
119 + }
120 + </style>
121 </head>
122 <body>
- <div class="editor-pane">
- <div id="editor"></div>
- </div>
-
- <div class="preview-pane">
- <iframe id="preview" sandbox="allow-scripts"></iframe>
- </div>
-
- <script type="module">
- let updateTimer;
- let editorView;
- const preview = document.getElementById('preview');
- const storageKey = 'html-lab-content';
-
- function updatePreview() {
- const code = editorView.state.doc.toString();
- const blob = new Blob([code], { type: 'text/html' });
- const url = URL.createObjectURL(blob);
- preview.src = url;
-
- // Clean up the previous URL to prevent memory leaks
- setTimeout(() => URL.revokeObjectURL(url), 1000);
- }
-
- function saveToStorage() {
- try {
- const code = editorView.state.doc.toString();
- localStorage.setItem(storageKey, code);
- } catch (e) {
- // Handle localStorage errors silently
- console.warn('Could not save to localStorage:', e);
- }
- }
-
- function loadFromStorage() {
- try {
- const saved = localStorage.getItem(storageKey);
- if (saved !== null) {
- // Handle old format that might be JSON
- try {
- const data = JSON.parse(saved);
- return data.text || data.html || saved;
- } catch (parseError) {
- return saved;
- }
- }
- } catch (e) {
- // Handle localStorage errors silently
- console.warn('Could not load from localStorage:', e);
- }
- return '';
- }
-
- // Save functionality with Cmd+S
- document.addEventListener('keydown', function(e) {
- if ((e.metaKey || e.ctrlKey) && e.key === 's') {
- e.preventDefault();
- saveFile();
- }
- });
-
- function saveFile() {
- const code = editorView.state.doc.toString();
- const blob = new Blob([code], { type: 'text/html' });
- const url = URL.createObjectURL(blob);
-
- const a = document.createElement('a');
- a.href = url;
- a.download = 'index.html';
- a.click();
-
- URL.revokeObjectURL(url);
- }
-
- // Wait for CodeMirror to be available
- function initializeCodeMirror() {
- if (!window.CodeMirror) {
- setTimeout(initializeCodeMirror, 100);
- return;
- }
-
- const {EditorView, EditorState, keymap, defaultKeymap, indentWithTab, html, githubDark} = window.CodeMirror;
-
- // Load saved content
- const savedContent = loadFromStorage();
-
- // Create CodeMirror editor
- editorView = new EditorView({
- state: EditorState.create({
- doc: savedContent,
- extensions: [
- keymap.of([indentWithTab, ...defaultKeymap]),
- html(),
- githubDark,
- EditorView.updateListener.of((update) => {
- if (update.docChanged) {
- clearTimeout(updateTimer);
- updateTimer = setTimeout(updatePreview, 500);
- saveToStorage();
- }
- })
- ]
- }),
- parent: document.getElementById('editor')
- });
-
- // Initial render
- updatePreview();
- }
-
- // Initialize when page loads
- initializeCodeMirror();
- </script>
123 + <div class="editor-pane">
124 + <div id="editor"></div>
125 + </div>
126 +
127 + <div class="preview-pane">
128 + <iframe id="preview" sandbox="allow-scripts"></iframe>
129 + </div>
130 +
131 + <script type="module">
132 + let updateTimer;
133 + let editorView;
134 + const preview = document.getElementById('preview');
135 + const storageKey = 'html-lab-content';
136 +
137 + function updatePreview() {
138 + const code = editorView.state.doc.toString();
139 + const blob = new Blob([code], { type: 'text/html' });
140 + const url = URL.createObjectURL(blob);
141 + preview.src = url;
142 +
143 + // Clean up the previous URL to prevent memory leaks
144 + setTimeout(() => URL.revokeObjectURL(url), 1000);
145 + }
146 +
147 + function saveToStorage() {
148 + try {
149 + const code = editorView.state.doc.toString();
150 + localStorage.setItem(storageKey, code);
151 + } catch (e) {
152 + // Handle localStorage errors silently
153 + console.warn('Could not save to localStorage:', e);
154 + }
155 + }
156 +
157 + function loadFromStorage() {
158 + try {
159 + const saved = localStorage.getItem(storageKey);
160 + if (saved !== null) {
161 + // Handle old format that might be JSON
162 + try {
163 + const data = JSON.parse(saved);
164 + return data.text || data.html || saved;
165 + } catch (parseError) {
166 + return saved;
167 + }
168 + }
169 + } catch (e) {
170 + // Handle localStorage errors silently
171 + console.warn('Could not load from localStorage:', e);
172 + }
173 + return '';
174 + }
175 +
176 + // Save functionality with Cmd+S
177 + document.addEventListener('keydown', function(e) {
178 + if ((e.metaKey || e.ctrlKey) && e.key === 's') {
179 + e.preventDefault();
180 + saveFile();
181 + }
182 + });
183 +
184 + function saveFile() {
185 + const code = editorView.state.doc.toString();
186 + const blob = new Blob([code], { type: 'text/html' });
187 + const url = URL.createObjectURL(blob);
188 +
189 + const a = document.createElement('a');
190 + a.href = url;
191 + a.download = 'index.html';
192 + a.click();
193 +
194 + URL.revokeObjectURL(url);
195 + }
196 +
197 + // Wait for CodeMirror to be available
198 + function initializeCodeMirror() {
199 + if (!window.CodeMirror) {
200 + setTimeout(initializeCodeMirror, 100);
201 + return;
202 + }
203 +
204 + const {EditorView, EditorState, keymap, defaultKeymap, indentWithTab, html, githubDark, indentUnit} = window.CodeMirror;
205 +
206 + // Load saved content
207 + const savedContent = loadFromStorage();
208 +
209 + // Create CodeMirror editor
210 + editorView = new EditorView({
211 + state: EditorState.create({
212 + doc: savedContent,
213 + extensions: [
214 + keymap.of([indentWithTab, ...defaultKeymap]),
215 + html(),
216 + githubDark,
217 + indentUnit.of("\t"),
218 + EditorView.updateListener.of((update) => {
219 + if (update.docChanged) {
220 + clearTimeout(updateTimer);
221 + updateTimer = setTimeout(updatePreview, 500);
222 + saveToStorage();
223 + }
224 + })
225 + ]
226 + }),
227 + parent: document.getElementById('editor')
228 + });
229 +
230 + // Initial render
231 + updatePreview();
232 + }
233 +
234 + // Initialize when page loads
235 + initializeCodeMirror();
236 + </script>
237 </body>
238 </html>