dshunt commited on
Commit
9c7adc0
·
verified ·
1 Parent(s): 39ea4da

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +525 -19
index.html CHANGED
@@ -1,19 +1,525 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Zero-Latency HTML Component Builder</title>
7
+
8
+ <!-- Fonts -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&family=Inter:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
12
+
13
+ <!-- Tailwind CSS -->
14
+ <script src="https://cdn.tailwindcss.com"></script>
15
+
16
+ <!-- Font Awesome -->
17
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
18
+
19
+ <!-- JSZip & FileSaver for downloads -->
20
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
21
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
22
+
23
+ <!-- Marked.js for Markdown parsing -->
24
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
25
+
26
+ <!-- Highlight.js for code syntax highlighting -->
27
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
28
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
29
+
30
+ <script>
31
+ tailwind.config = {
32
+ theme: {
33
+ extend: {
34
+ fontFamily: {
35
+ 'display': ['Outfit', 'sans-serif'],
36
+ 'body': ['Inter', 'sans-serif'],
37
+ 'mono': ['"IBM Plex Mono"', 'monospace'],
38
+ },
39
+ colors: {
40
+ brand: {
41
+ 50: '#f5f1ff',
42
+ 100: '#ebe5ff',
43
+ 200: '#d9ceff',
44
+ 300: '#bdaaff',
45
+ 400: '#9e7cff',
46
+ 500: '#8248ff',
47
+ 600: '#7c3aed',
48
+ 700: '#6d28d9',
49
+ 800: '#5b21b6',
50
+ 900: '#4c1d95',
51
+ },
52
+ slate: {
53
+ 850: '#1a1f2e',
54
+ 900: '#111827',
55
+ 950: '#0b0f19',
56
+ }
57
+ },
58
+ boxShadow: {
59
+ 'glow': '0 0 40px -10px rgba(124, 58, 237, 0.3)',
60
+ 'glow-sm': '0 0 20px -5px rgba(124, 58, 237, 0.2)',
61
+ 'card': '0 8px 32px -8px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.04)',
62
+ 'panel': '0 4px 24px -4px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.04)',
63
+ 'panel-inset': 'inset 0 2px 8px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.03)',
64
+ }
65
+ }
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <style>
71
+ /* ========== Custom Scrollbar ========== */
72
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
73
+ ::-webkit-scrollbar-track { background: transparent; }
74
+ ::-webkit-scrollbar-thumb { background: rgba(124, 58, 237, 0.15); border-radius: 10px; }
75
+ ::-webkit-scrollbar-thumb:hover { background: rgba(124, 58, 237, 0.3); }
76
+
77
+ /* ========== Smooth Selection ========== */
78
+ ::selection { background: rgba(124, 58, 237, 0.25); color: #e2e8f0; }
79
+
80
+ /* ========== Editor Specific ========== */
81
+ .editor-line {
82
+ position: absolute;
83
+ left: 0;
84
+ right: 0;
85
+ pointer-events: none;
86
+ color: #4b5563;
87
+ font-family: 'IBM Plex Mono', monospace;
88
+ font-size: 13px;
89
+ line-height: 24px;
90
+ padding-left: 16px;
91
+ padding-right: 16px;
92
+ white-space: pre-wrap;
93
+ word-break: break-all;
94
+ overflow: hidden;
95
+ border-left: 3px solid transparent;
96
+ transition: border-color 0.15s ease, background-color 0.15s ease;
97
+ }
98
+ .editor-line.active {
99
+ background: rgba(124, 58, 237, 0.06);
100
+ border-left-color: #8248ff;
101
+ }
102
+
103
+ /* ========== Syntax Highlighting (Custom Override) ========== */
104
+ .token-keyword { color: #c084fc; font-weight: 500; }
105
+ .token-string { color: #86efac; }
106
+ .token-number { color: #67e8f9; }
107
+ .token-comment { color: #6b7280; font-style: italic; }
108
+ .token-tag { color: #f472b6; }
109
+ .token-attr { color: #60a5fa; }
110
+ .token-func { color: #fbbf24; }
111
+
112
+ /* ========== Animations ========== */
113
+ @keyframes slideUp { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
114
+ @keyframes slideDown { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
115
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
116
+ @keyframes pulse-glow { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }
117
+ @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
118
+ @keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.02); } }
119
+ @keyframes spin-slow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
120
+
121
+ .animate-slide-up { animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
122
+ .animate-slide-down { animation: slideDown 0.4s ease-out forwards; }
123
+ .animate-fade-in { animation: fadeIn 0.4s ease-out forwards; }
124
+ .animate-float { animation: float 3s ease-in-out infinite; }
125
+ .animate-breathe { animation: breathe 4s ease-in-out infinite; }
126
+ .animate-spin-slow { animation: spin-slow 8s linear infinite; }
127
+
128
+ /* ========== Glass Morphism ========== */
129
+ .glass {
130
+ background: rgba(17, 24, 39, 0.7);
131
+ backdrop-filter: blur(20px) saturate(180%);
132
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
133
+ }
134
+ .glass-light {
135
+ background: rgba(255, 255, 255, 0.03);
136
+ backdrop-filter: blur(12px);
137
+ -webkit-backdrop-filter: blur(12px);
138
+ }
139
+
140
+ /* ========== Preview Iframe ========== */
141
+ .preview-frame {
142
+ width: 100%;
143
+ height: 100%;
144
+ border: none;
145
+ background: #ffffff;
146
+ }
147
+ .dark-mode .preview-frame {
148
+ background: #0f172a;
149
+ filter: invert(1) hue-rotate(180deg);
150
+ }
151
+
152
+ /* ========== Toast ========== */
153
+ .toast-enter { animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
154
+ .toast-exit { animation: slideDown 0.3s ease-in forwards; }
155
+
156
+ /* ========== Resize Handle ========== */
157
+ .resize-handle {
158
+ cursor: col-resize;
159
+ width: 6px;
160
+ background: transparent;
161
+ transition: background 0.2s;
162
+ }
163
+ .resize-handle:hover, .resize-handle:active {
164
+ background: rgba(124, 58, 237, 0.4);
165
+ }
166
+
167
+ /* ========== Misc ========== */
168
+ .no-select { user-select: none; -webkit-user-select: none; }
169
+ .line-clamp-1 { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
170
+
171
+ /* Preview Document styles */
172
+ .preview-container {
173
+ background: #f8fafc;
174
+ background-image:
175
+ linear-gradient(rgba(226, 232, 240, 0.4) 1px, transparent 1px),
176
+ linear-gradient(90deg, rgba(226, 232, 240, 0.4) 1px, transparent 1px);
177
+ background-size: 20px 20px;
178
+ }
179
+
180
+ /* Dark checker pattern for dark mode */
181
+ .dark-mode .preview-container {
182
+ background: #0f172a;
183
+ background-image:
184
+ linear-gradient(rgba(30, 41, 59, 0.6) 1px, transparent 1px),
185
+ linear-gradient(90deg, rgba(30, 41, 59, 0.6) 1px, transparent 1px);
186
+ }
187
+ </style>
188
+ </head>
189
+ <body class="bg-slate-950 text-slate-300 font-body overflow-hidden antialiased">
190
+ <div id="app" class="h-screen w-full flex flex-col">
191
+
192
+ <!-- ═══════════ HEADER ═══════════ -->
193
+ <header class="glass relative z-50 flex-shrink-0 border-b border-white/[0.04]">
194
+ <!-- Top Bar -->
195
+ <div class="flex items-center justify-between px-5 py-3">
196
+ <div class="flex items-center gap-4">
197
+ <div class="relative group">
198
+ <div class="absolute inset-0 bg-gradient-to-br from-brand-500 to-purple-400 rounded-xl blur opacity-40 group-hover:opacity-60 transition-opacity duration-300"></div>
199
+ <div class="relative w-10 h-10 bg-gradient-to-br from-brand-600 to-brand-500 rounded-xl flex items-center justify-center shadow-glow-sm cursor-pointer transform hover:scale-105 transition-all duration-300">
200
+ <i class="fa-solid fa-code text-white text-sm"></i>
201
+ </div>
202
+ </div>
203
+ <div class="flex flex-col">
204
+ <h1 class="font-display font-bold text-white text-base tracking-tight leading-tight">VibeBuilder <span class="text-brand-400 text-xs font-medium ml-1 align-top">v2.0</span></h1>
205
+ <p class="text-[11px] text-slate-500 font-medium tracking-wide uppercase">Zero-Latency Component Engine</p>
206
+ </div>
207
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="ml-4 px-3 py-1.5 text-[11px] font-medium text-slate-400 hover:text-brand-300 bg-white/[0.03] hover:bg-brand-500/10 border border-white/[0.05] hover:border-brand-500/20 rounded-lg transition-all duration-300">
208
+ <i class="fa-solid fa-bolt mr-1.5 text-brand-400"></i>Built with anycoder
209
+ </a>
210
+ </div>
211
+
212
+ <div class="flex items-center gap-2">
213
+ <!-- Preview Link -->
214
+ <button id="btn-preview-link" onclick="generatePreviewLink()" class="group flex items-center gap-2 px-4 py-2 text-xs font-semibold text-slate-300 bg-white/[0.03] hover:bg-white/[0.06] border border-white/[0.06] hover:border-white/[0.1] rounded-lg transition-all duration-200 active:scale-95">
215
+ <i class="fa-solid fa-link text-[10px] text-slate-500 group-hover:text-brand-400 transition-colors"></i>
216
+ <span>Copy Link</span>
217
+ </button>
218
+
219
+ <!-- Download Dropdown -->
220
+ <div class="relative" id="download-dropdown">
221
+ <button onclick="toggleDownloadDropdown()" class="flex items-center gap-2 px-4 py-2 text-xs font-semibold text-white bg-gradient-to-r from-brand-600 to-purple-600 hover:from-brand-500 hover:to-purple-500 rounded-lg shadow-glow-sm hover:shadow-glow transition-all duration-300 active:scale-95 border border-white/10">
222
+ <i class="fa-solid fa-cloud-arrow-down"></i>
223
+ <span>Export</span>
224
+ <i class="fa-solid fa-chevron-down text-[10px] opacity-60"></i>
225
+ </button>
226
+ <div id="download-menu" class="hidden absolute right-0 top-full mt-2 w-56 bg-slate-900/95 backdrop-blur-xl border border-white/[0.06] rounded-xl shadow-2xl overflow-hidden z-50 animate-slide-down">
227
+ <div class="px-4 py-3 border-b border-white/[0.04]">
228
+ <p class="text-[10px] font-semibold text-slate-500 uppercase tracking-wider">Export Options</p>
229
+ </div>
230
+ <button onclick="downloadFile('index.html')" class="w-full flex items-center gap-3 px-4 py-3 text-sm text-slate-300 hover:text-white hover:bg-white/[0.04] transition-colors text-left group">
231
+ <i class="fa-brands fa-html5 text-orange-400 group-hover:scale-110 transition-transform"></i>
232
+ <div>
233
+ <p class="font-medium">index.html</p>
234
+ <p class="text-[10px] text-slate-500">Single bundled file</p>
235
+ </div>
236
+ </button>
237
+ <button onclick="downloadFile('style.css')" class="w-full flex items-center gap-3 px-4 py-3 text-sm text-slate-300 hover:text-white hover:bg-white/[0.04] transition-colors text-left group">
238
+ <i class="fa-brands fa-css3-alt text-blue-400 group-hover:scale-110 transition-transform"></i>
239
+ <div>
240
+ <p class="font-medium">style.css</p>
241
+ <p class="text-[10px] text-slate-500">Stylesheet only</p>
242
+ </div>
243
+ </button>
244
+ <button onclick="downloadFile('script.js')" class="w-full flex items-center gap-3 px-4 py-3 text-sm text-slate-300 hover:text-white hover:bg-white/[0.04] transition-colors text-left group">
245
+ <i class="fa-brands fa-js text-yellow-400 group-hover:scale-110 transition-transform"></i>
246
+ <div>
247
+ <p class="font-medium">script.js</p>
248
+ <p class="text-[10px] text-slate-500">JavaScript only</p>
249
+ </div>
250
+ </button>
251
+ <div class="border-t border-white/[0.04]"></div>
252
+ <button onclick="downloadAll()" class="w-full flex items-center gap-3 px-4 py-3 text-sm text-brand-300 hover:text-brand-200 hover:bg-brand-500/10 transition-colors text-left group">
253
+ <i class="fa-solid fa-file-zipper text-brand-400 group-hover:scale-110 transition-transform"></i>
254
+ <div>
255
+ <p class="font-medium">Full Project (.zip)</p>
256
+ <p class="text-[10px] text-slate-500">All files + README</p>
257
+ </div>
258
+ </button>
259
+ </div>
260
+ </div>
261
+ </div>
262
+ </div>
263
+
264
+ <!-- Toolbar -->
265
+ <div class="flex items-center gap-2 px-5 py-2 bg-slate-950/50 border-t border-white/[0.03]">
266
+ <!-- File Tabs -->
267
+ <div id="file-tabs" class="flex items-center gap-1.5 flex-1 overflow-x-auto no-scrollbar">
268
+ <!-- Dynamic tabs injected here -->
269
+ </div>
270
+
271
+ <div class="flex items-center gap-1.5 ml-2 pl-2 border-l border-white/[0.06]">
272
+ <button onclick="addNewFile()" class="p-1.5 text-slate-500 hover:text-white hover:bg-white/[0.06] rounded-md transition-all text-xs" title="New File">
273
+ <i class="fa-solid fa-plus"></i>
274
+ </button>
275
+ <button onclick="toggleSplitView()" class="p-1.5 text-slate-500 hover:text-white hover:bg-white/[0.06] rounded-md transition-all text-xs" title="Toggle Split">
276
+ <i class="fa-solid fa-columns"></i>
277
+ </button>
278
+ <button onclick="toggleTheme()" class="p-1.5 text-slate-500 hover:text-yellow-400 hover:bg-white/[0.06] rounded-md transition-all text-xs" title="Toggle Theme">
279
+ <i class="fa-solid fa-sun"></i>
280
+ </button>
281
+ <button onclick="toggleSettings()" class="p-1.5 text-slate-500 hover:text-white hover:bg-white/[0.06] rounded-md transition-all text-xs" title="Settings">
282
+ <i class="fa-solid fa-gear"></i>
283
+ </button>
284
+ <div class="w-px h-4 bg-white/[0.06] mx-1"></div>
285
+ <button onclick="runCode()" class="px-3 py-1.5 text-xs font-semibold text-white bg-brand-600/80 hover:bg-brand-500 rounded-md transition-all shadow-glow-sm active:scale-95 flex items-center gap-1.5">
286
+ <i class="fa-solid fa-play text-[10px]"></i> Run
287
+ </button>
288
+ <button onclick="toggleAutoRefresh()" id="auto-refresh-btn" class="px-2 py-1.5 text-xs font-medium text-slate-500 hover:text-brand-400 bg-white/[0.03] hover:bg-brand-500/10 rounded-md transition-all border border-transparent hover:border-brand-500/20">
289
+ <i class="fa-solid fa-rotate text-[10px]"></i> Auto
290
+ </button>
291
+ </div>
292
+ </div>
293
+ </header>
294
+
295
+ <!-- ═══════════ MAIN WORKSPACE ═══════════ -->
296
+ <main id="workspace" class="flex-1 flex overflow-hidden relative">
297
+ <!-- Editor Panel -->
298
+ <div id="editor-panel" class="flex flex-col bg-[#0d1117] border-r border-white/[0.04] transition-all duration-300" style="width: 50%;">
299
+ <!-- Editor Toolbar -->
300
+ <div class="flex items-center justify-between px-4 py-2 bg-[#0a0e14] border-b border-white/[0.04]">
301
+ <div class="flex items-center gap-2">
302
+ <span id="current-file-label" class="text-[11px] font-mono text-brand-400 font-medium"></span>
303
+ <span class="text-[10px] text-slate-600 font-mono" id="cursor-position">Ln 1, Col 1</span>
304
+ </div>
305
+ <div class="flex items-center gap-1">
306
+ <button onclick="formatCode()" class="text-[10px] text-slate-500 hover:text-brand-400 px-2 py-0.5 rounded hover:bg-white/[0.04] transition-all" title="Format Code">
307
+ <i class="fa-solid fa-align-left mr-1"></i>Format
308
+ </button>
309
+ <button onclick="copyCode()" class="text-[10px] text-slate-500 hover:text-brand-400 px-2 py-0.5 rounded hover:bg-white/[0.04] transition-all" title="Copy">
310
+ <i class="fa-regular fa-copy mr-1"></i>Copy
311
+ </button>
312
+ <button onclick="clearEditor()" class="text-[10px] text-slate-500 hover:text-red-400 px-2 py-0.5 rounded hover:bg-white/[0.04] transition-all" title="Clear">
313
+ <i class="fa-solid fa-eraser mr-1"></i>Clear
314
+ </button>
315
+ </div>
316
+ </div>
317
+
318
+ <!-- Editor Area -->
319
+ <div class="flex-1 relative overflow-hidden group">
320
+ <div id="editor-container" class="absolute inset-0 overflow-auto font-mono text-[13px] leading-6">
321
+ <div id="editor-content" class="relative min-h-full pb-20"></div>
322
+ </div>
323
+ <!-- Floating Line Counter (right side) -->
324
+ <div class="absolute right-3 top-3 text-[10px] text-slate-600 font-mono opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none">
325
+ <span id="total-lines">0</span> lines
326
+ </div>
327
+ </div>
328
+ </div>
329
+
330
+ <!-- Resize Handle -->
331
+ <div class="resize-handle z-10 flex-shrink-0" id="resize-handle"></div>
332
+
333
+ <!-- Preview Panel -->
334
+ <div id="preview-panel" class="flex-1 flex flex-col relative preview-container transition-all duration-300">
335
+ <!-- Preview Toolbar -->
336
+ <div class="flex items-center justify-between px-4 py-2 glass border-b border-white/[0.04] z-10">
337
+ <div class="flex items-center gap-3">
338
+ <span class="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">Live Preview</span>
339
+ <div id="preview-badge" class="flex items-center gap-1.5 px-2 py-0.5 bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 rounded-full text-[10px] font-medium opacity-0 transition-opacity duration-300">
340
+ <span class="w-1.5 h-1.5 bg-emerald-400 rounded-full animate-pulse"></span>
341
+ Live
342
+ </div>
343
+ </div>
344
+ <div class="flex items-center gap-1.5">
345
+ <button onclick="setPreviewDevice('desktop')" class="p-1.5 text-slate-500 hover:text-white rounded-md transition-all text-xs preview-device-btn active" data-device="desktop" title="Desktop">
346
+ <i class="fa-solid fa-desktop"></i>
347
+ </button>
348
+ <button onclick="setPreviewDevice('tablet')" class="p-1.5 text-slate-500 hover:text-white rounded-md transition-all text-xs preview-device-btn" data-device="tablet" title="Tablet">
349
+ <i class="fa-solid fa-tablet-screen-button"></i>
350
+ </button>
351
+ <button onclick="setPreviewDevice('mobile')" class="p-1.5 text-slate-500 hover:text-white rounded-md transition-all text-xs preview-device-btn" data-device="mobile" title="Mobile">
352
+ <i class="fa-solid fa-mobile-screen-button"></i>
353
+ </button>
354
+ <div class="w-px h-4 bg-white/[0.06] mx-1"></div>
355
+ <button onclick="openFullscreen()" class="p-1.5 text-slate-500 hover:text-white rounded-md transition-all text-xs" title="Fullscreen">
356
+ <i class="fa-solid fa-expand"></i>
357
+ </button>
358
+ <button onclick="refreshPreview()" class="p-1.5 text-slate-500 hover:text-brand-400 rounded-md transition-all text-xs" title="Refresh">
359
+ <i class="fa-solid fa-rotate-right"></i>
360
+ </button>
361
+ </div>
362
+ </div>
363
+
364
+ <!-- Preview Content -->
365
+ <div class="flex-1 overflow-auto relative">
366
+ <div id="preview-wrapper" class="w-full h-full p-6 flex justify-center items-start transition-all duration-500">
367
+ <iframe id="preview-frame" class="preview-frame rounded-xl shadow-2xl transition-all duration-500" sandbox="allow-scripts allow-same-origin allow-forms allow-modals allow-popups"></iframe>
368
+ </div>
369
+ </div>
370
+ </div>
371
+ </main>
372
+
373
+ <!-- ═══════════ FILE LIST SIDEBAR (Collapsible) ═══════════ -->
374
+ <div id="file-sidebar" class="fixed left-0 top-[104px] bottom-0 w-56 bg-slate-900/95 backdrop-blur-xl border-r border-white/[0.04] z-40 transform -translate-x-full transition-transform duration-300 shadow-2xl flex flex-col">
375
+ <div class="p-4 border-b border-white/[0.04]">
376
+ <h3 class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider">Project Files</h3>
377
+ </div>
378
+ <div id="file-list" class="flex-1 overflow-y-auto py-2">
379
+ <!-- File list items injected here -->
380
+ </div>
381
+ <div class="p-3 border-t border-white/[0.04]">
382
+ <button onclick="addNewFile()" class="w-full flex items-center justify-center gap-2 px-3 py-2 text-xs font-medium text-brand-300 hover:text-brand-200 bg-brand-500/10 hover:bg-brand-500/15 border border-brand-500/20 rounded-lg transition-all">
383
+ <i class="fa-solid fa-plus text-[10px]"></i> New File
384
+ </button>
385
+ </div>
386
+ </div>
387
+
388
+ <!-- ═══════════ TOAST NOTIFICATIONS ═══════════ -->
389
+ <div id="toast-container" class="fixed bottom-6 right-6 z-[100] flex flex-col gap-2 pointer-events-none"></div>
390
+
391
+ <!-- ═══════════ MODALS ═══════════ -->
392
+
393
+ <!-- New File Modal -->
394
+ <div id="new-file-modal" class="hidden fixed inset-0 z-[60] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in">
395
+ <div class="bg-slate-900 border border-white/[0.08] rounded-2xl shadow-2xl w-96 overflow-hidden transform transition-all animate-slide-up">
396
+ <div class="p-5 border-b border-white/[0.04]">
397
+ <h3 class="text-base font-display font-bold text-white">New File</h3>
398
+ <p class="text-xs text-slate-500 mt-1">Create a new file in your project</p>
399
+ </div>
400
+ <div class="p-5 space-y-4">
401
+ <div>
402
+ <label class="block text-[11px] font-semibold text-slate-400 uppercase tracking-wider mb-2">File Name</label>
403
+ <input type="text" id="new-file-name" class="w-full bg-slate-950 border border-white/[0.08] rounded-lg px-3 py-2.5 text-sm text-white placeholder-slate-600 focus:border-brand-500 focus:ring-1 focus:ring-brand-500/20 outline-none transition-all font-mono" placeholder="component.html" onkeydown="if(event.key==='Enter') confirmNewFile()">
404
+ <p class="text-[10px] text-slate-500 mt-1.5">Supported: .html, .css, .js, .md, .json, .txt</p>
405
+ </div>
406
+ </div>
407
+ <div class="flex items-center gap-2 p-5 border-t border-white/[0.04] bg-slate-950/30">
408
+ <button onclick="closeModal('new-file-modal')" class="flex-1 px-4 py-2 text-xs font-medium text-slate-400 hover:text-white bg-white/[0.03] hover:bg-white/[0.06] rounded-lg transition-all">Cancel</button>
409
+ <button onclick="confirmNewFile()" class="flex-1 px-4 py-2 text-xs font-semibold text-white bg-brand-600 hover:bg-brand-500 rounded-lg transition-all shadow-glow-sm">Create File</button>
410
+ </div>
411
+ </div>
412
+ </div>
413
+
414
+ <!-- Preview Link Modal -->
415
+ <div id="link-modal" class="hidden fixed inset-0 z-[60] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in">
416
+ <div class="bg-slate-900 border border-white/[0.08] rounded-2xl shadow-2xl w-[480px] overflow-hidden transform transition-all animate-slide-up">
417
+ <div class="p-5 border-b border-white/[0.04] flex items-center justify-between">
418
+ <div>
419
+ <h3 class="text-base font-display font-bold text-white">Share Preview</h3>
420
+ <p class="text-xs text-slate-500 mt-1">Generate a shareable preview link</p>
421
+ </div>
422
+ <button onclick="closeModal('link-modal')" class="text-slate-500 hover:text-white transition-colors">
423
+ <i class="fa-solid fa-xmark"></i>
424
+ </button>
425
+ </div>
426
+ <div class="p-5 space-y-4">
427
+ <div>
428
+ <label class="block text-[11px] font-semibold text-slate-400 uppercase tracking-wider mb-2">Preview URL</label>
429
+ <div class="flex gap-2">
430
+ <input type="text" id="preview-url" readonly class="flex-1 bg-slate-950 border border-white/[0.08] rounded-lg px-3 py-2.5 text-xs text-slate-400 font-mono focus:border-brand-500 outline-none transition-all" value="">
431
+ <button onclick="copyPreviewUrl()" class="px-3 py-2 text-xs font-medium text-brand-300 hover:text-brand-200 bg-brand-500/10 hover:bg-brand-500/15 border border-brand-500/20 rounded-lg transition-all">
432
+ <i class="fa-regular fa-copy"></i>
433
+ </button>
434
+ </div>
435
+ </div>
436
+ <div class="bg-slate-950/50 rounded-lg p-4 border border-white/[0.04]">
437
+ <p class="text-[11px] text-slate-500 leading-relaxed">
438
+ <i class="fa-solid fa-circle-info text-brand-400 mr-1.5"></i>
439
+ This link contains a Base64-encoded version of your code. Anyone with this link can view your preview. The link is generated locally in your browser - no data is sent to any server.
440
+ </p>
441
+ </div>
442
+ </div>
443
+ </div>
444
+ </div>
445
+
446
+ <!-- Settings Modal -->
447
+ <div id="settings-modal" class="hidden fixed inset-0 z-[60] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in">
448
+ <div class="bg-slate-900 border border-white/[0.08] rounded-2xl shadow-2xl w-96 overflow-hidden transform transition-all animate-slide-up">
449
+ <div class="p-5 border-b border-white/[0.04]">
450
+ <h3 class="text-base font-display font-bold text-white">Editor Settings</h3>
451
+ </div>
452
+ <div class="p-5 space-y-4">
453
+ <div class="flex items-center justify-between">
454
+ <label class="text-sm text-slate-300">Auto Refresh</label>
455
+ <button onclick="toggleSetting('autoRefresh')" id="setting-auto-refresh" class="w-10 h-5 bg-brand-600 rounded-full relative transition-all">
456
+ <span class="absolute right-1 top-0.5 w-4 h-4 bg-white rounded-full shadow transition-all"></span>
457
+ </button>
458
+ </div>
459
+ <div class="flex items-center justify-between">
460
+ <label class="text-sm text-slate-300">Line Numbers</label>
461
+ <button onclick="toggleSetting('lineNumbers')" id="setting-line-numbers" class="w-10 h-5 bg-brand-600 rounded-full relative transition-all">
462
+ <span class="absolute right-1 top-0.5 w-4 h-4 bg-white rounded-full shadow transition-all"></span>
463
+ </button>
464
+ </div>
465
+ <div class="flex items-center justify-between">
466
+ <label class="text-sm text-slate-300">Dark Preview</label>
467
+ <button onclick="toggleSetting('darkPreview')" id="setting-dark-preview" class="w-10 h-5 bg-slate-700 rounded-full relative transition-all">
468
+ <span class="absolute left-1 top-0.5 w-4 h-4 bg-white rounded-full shadow transition-all"></span>
469
+ </button>
470
+ </div>
471
+ <div class="flex items-center justify-between">
472
+ <label class="text-sm text-slate-300">Font Size</label>
473
+ <div class="flex items-center gap-2">
474
+ <button onclick="changeFontSize(-1)" class="w-7 h-7 flex items-center justify-center text-xs text-slate-400 hover:text-white bg-white/[0.04] hover:bg-white/[0.08] rounded-md transition-all">-</button>
475
+ <span id="font-size-display" class="text-xs font-mono text-slate-400 w-8 text-center">13</span>
476
+ <button onclick="changeFontSize(1)" class="w-7 h-7 flex items-center justify-center text-xs text-slate-400 hover:text-white bg-white/[0.04] hover:bg-white/[0.08] rounded-md transition-all">+</button>
477
+ </div>
478
+ </div>
479
+ </div>
480
+ <div class="p-5 border-t border-white/[0.04] bg-slate-950/30">
481
+ <button onclick="closeModal('settings-modal')" class="w-full px-4 py-2 text-xs font-semibold text-white bg-brand-600 hover:bg-brand-500 rounded-lg transition-all shadow-glow-sm">Done</button>
482
+ </div>
483
+ </div>
484
+ </div>
485
+
486
+ </div>
487
+
488
+ <script>
489
+ // ═══════════════════════════════════════════════════════
490
+ // STATE MANAGEMENT
491
+ // ═══════════════════════════════════════════════════════
492
+
493
+ let files = {
494
+ 'index.html': {
495
+ content: `<!DOCTYPE html>
496
+ <html lang="en">
497
+ <head>
498
+ <meta charset="UTF-8">
499
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
500
+ <title>My Awesome Component</title>
501
+ <link rel="stylesheet" href="style.css">
502
+ </head>
503
+ <body>
504
+ <div class="hero">
505
+ <div class="card">
506
+ <div class="avatar">
507
+ <img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&h=150&fit=crop&crop=face" alt="Profile">
508
+ </div>
509
+ <h1>Sarah Mitchell</h1>
510
+ <p class="role">Product Designer</p>
511
+ <p class="bio">Crafting delightful digital experiences with pixel-perfect precision and a passion for user-centered design.</p>
512
+ <div class="stats">
513
+ <div><span>128</span><small>Projects</small></div>
514
+ <div><span>4.2k</span><small>Followers</small></div>
515
+ <div><span>86</span><small>Reviews</small></div>
516
+ </div>
517
+ <button class="cta" onclick="alert('Connected!')">
518
+ <span>Connect</span>
519
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
520
+ </button>
521
+ </div>
522
+ </div>
523
+ <script src="script.js"><\/script>
524
+ </body>
525
+ </html>