HedronCreeper commited on
Commit
33c9aaf
·
verified ·
1 Parent(s): 287ad78

Update static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +194 -50
static/index.html CHANGED
@@ -26,13 +26,7 @@
26
  letter-spacing: -1px;
27
  }
28
  p.sub { color: #555570; font-size: 0.9rem; margin-top: -1.5rem; text-align: center; }
29
- .row {
30
- display: flex;
31
- gap: 1.5rem;
32
- width: 100%;
33
- max-width: 900px;
34
- flex-wrap: wrap;
35
- }
36
  .card {
37
  background: #10101e;
38
  border: 1px solid #222238;
@@ -104,12 +98,28 @@
104
  }
105
  button:hover { opacity: 0.85; }
106
  button:disabled { opacity: 0.4; cursor: not-allowed; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  .status { font-size: 0.8rem; color: #555570; text-align: center; min-height: 1em; }
108
  .status.error { color: #ef4444; }
109
  .status.success { color: #22c55e; }
110
  .preview { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }
111
  .preview img { max-width: 160px; border-radius: 8px; border: 1px solid #222238; image-rendering: pixelated; }
112
  .download { font-size: 0.8rem; color: #a78bfa; cursor: pointer; text-decoration: underline; }
 
113
  .decoded-text {
114
  background: #080810;
115
  border: 1px solid #222238;
@@ -119,10 +129,50 @@
119
  color: #e0e0f0;
120
  word-break: break-all;
121
  white-space: pre-wrap;
 
 
122
  display: none;
123
  }
124
  .decoded-image { display: none; flex-direction: column; align-items: center; gap: 0.5rem; }
125
  .decoded-image img { max-width: 100%; border-radius: 8px; border: 1px solid #222238; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  </style>
127
  </head>
128
  <body>
@@ -134,17 +184,17 @@
134
  <h2>Encode</h2>
135
  <div class="tabs">
136
  <div class="tab active" onclick="switchTab('text')">Text</div>
137
- <div class="tab" onclick="switchTab('image')">Image</div>
138
  </div>
139
 
140
  <div class="panel active" id="panel-text">
141
- <textarea id="encodeInput" placeholder="Type a message..."></textarea>
142
  </div>
143
 
144
- <div class="panel" id="panel-image">
145
- <div class="upload-zone" id="uploadZone" onclick="document.getElementById('imageUpload').click()">
146
- <input type="file" id="imageUpload" accept="image/*" onchange="handleImageUpload(this)">
147
- <span id="uploadLabel">Click to upload image (max 2MB)</span>
148
  </div>
149
  </div>
150
 
@@ -161,51 +211,87 @@
161
  </div>
162
  <button id="decodeBtn" onclick="decodeImage()">Extract</button>
163
  <div class="status" id="decodeStatus"></div>
 
164
  <div class="decoded-text" id="decodedText"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  <div class="decoded-image" id="decodedImage">
166
  <img id="decodedImg" src="" alt="decoded">
167
- <span class="download" onclick="downloadDecoded()">Download Image</span>
 
 
 
 
 
 
168
  </div>
169
  </div>
170
  </div>
171
 
172
  <script>
173
  let activeTab = "text";
174
- let uploadedImageFile = null;
175
- let decodedImageSrc = null;
 
 
176
  let encodedSrc = null;
177
 
178
  function switchTab(tab) {
179
  activeTab = tab;
180
  document.querySelectorAll(".tab").forEach((t, i) => {
181
- t.classList.toggle("active", (i === 0 && tab === "text") || (i === 1 && tab === "image"));
182
  });
183
  document.getElementById("panel-text").classList.toggle("active", tab === "text");
184
- document.getElementById("panel-image").classList.toggle("active", tab === "image");
185
  document.getElementById("encodeStatus").textContent = "";
186
  document.getElementById("encodePreview").innerHTML = "";
187
  }
188
 
189
- function handleImageUpload(input) {
190
  const file = input.files[0];
191
  const zone = document.getElementById("uploadZone");
192
  const label = document.getElementById("uploadLabel");
193
  if (!file) return;
194
- if (file.size > 2 * 1024 * 1024) {
195
  zone.className = "upload-zone has-error";
196
- label.textContent = `Too large: ${(file.size / 1024 / 1024).toFixed(2)}MB. Max is 2MB.`;
197
- uploadedImageFile = null;
198
  return;
199
  }
200
- uploadedImageFile = file;
201
  zone.className = "upload-zone has-file";
202
- label.textContent = `${file.name} (${(file.size / 1024).toFixed(1)}KB)`;
203
  }
204
 
205
  function handleDecodeUpload(input) {
206
  const file = input.files[0];
207
- const label = document.getElementById("decodeLabel");
208
- if (file) label.textContent = file.name;
209
  }
210
 
211
  async function encode() {
@@ -227,24 +313,24 @@
227
  });
228
  const data = await res.json();
229
  if (data.image) {
230
- showEncodedResult(data.image);
231
  status.className = "status success";
232
- status.textContent = "Encoded! Looks like a normal image.";
233
  } else {
234
  status.className = "status error";
235
  status.textContent = "Error: " + (data.error || "Unknown");
236
  }
237
  } else {
238
- if (!uploadedImageFile) { status.textContent = "Upload an image first."; btn.disabled = false; return; }
239
  status.textContent = "Encoding...";
240
  const form = new FormData();
241
- form.append("file", uploadedImageFile);
242
- const res = await fetch("/encode/image", { method: "POST", body: form });
243
  const data = await res.json();
244
  if (data.image) {
245
- showEncodedResult(data.image);
246
  status.className = "status success";
247
- status.textContent = "Image encoded!";
248
  } else {
249
  status.className = "status error";
250
  status.textContent = "Error: " + (data.error || "Unknown");
@@ -253,7 +339,7 @@
253
  btn.disabled = false;
254
  }
255
 
256
- function showEncodedResult(b64) {
257
  encodedSrc = "data:image/png;base64," + b64;
258
  const preview = document.getElementById("encodePreview");
259
  const img = document.createElement("img");
@@ -262,20 +348,36 @@
262
  dl.className = "download";
263
  dl.textContent = "Download ChromaCode PNG";
264
  dl.onclick = () => { const a = document.createElement("a"); a.href = encodedSrc; a.download = "chromacode.png"; a.click(); };
 
 
 
265
  preview.appendChild(img);
266
  preview.appendChild(dl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  }
268
 
269
  async function decodeImage() {
270
  const file = document.getElementById("decodeFile").files[0];
271
  if (!file) return;
272
  const status = document.getElementById("decodeStatus");
273
- const textOut = document.getElementById("decodedText");
274
- const imgOut = document.getElementById("decodedImage");
275
  const btn = document.getElementById("decodeBtn");
 
276
  status.className = "status";
277
- textOut.style.display = "none";
278
- imgOut.style.display = "none";
279
  btn.disabled = true;
280
  status.textContent = "Extracting...";
281
 
@@ -285,16 +387,47 @@
285
  const data = await res.json();
286
 
287
  if (data.type === "text") {
288
- textOut.textContent = data.text;
289
- textOut.style.display = "block";
290
- status.className = "status success";
291
- status.textContent = "Text extracted!";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  } else if (data.type === "image") {
293
- decodedImageSrc = "data:image/png;base64," + data.image;
294
- document.getElementById("decodedImg").src = decodedImageSrc;
295
- imgOut.style.display = "flex";
 
 
296
  status.className = "status success";
297
  status.textContent = "Image extracted!";
 
 
 
 
 
 
298
  } else {
299
  status.className = "status error";
300
  status.textContent = "Error: " + (data.error || "Unknown");
@@ -302,13 +435,24 @@
302
  btn.disabled = false;
303
  }
304
 
305
- function downloadDecoded() {
306
- if (!decodedImageSrc) return;
 
 
 
 
 
 
 
 
 
 
 
307
  const a = document.createElement("a");
308
- a.href = decodedImageSrc;
309
- a.download = "decoded.png";
310
  a.click();
311
  }
312
  </script>
313
  </body>
314
- </html>
 
26
  letter-spacing: -1px;
27
  }
28
  p.sub { color: #555570; font-size: 0.9rem; margin-top: -1.5rem; text-align: center; }
29
+ .row { display: flex; gap: 1.5rem; width: 100%; max-width: 960px; flex-wrap: wrap; }
 
 
 
 
 
 
30
  .card {
31
  background: #10101e;
32
  border: 1px solid #222238;
 
98
  }
99
  button:hover { opacity: 0.85; }
100
  button:disabled { opacity: 0.4; cursor: not-allowed; }
101
+ .btn-row { display: flex; gap: 0.5rem; }
102
+ .btn-small {
103
+ flex: 1;
104
+ padding: 0.5rem;
105
+ background: #1a1a30;
106
+ border: 1px solid #222238;
107
+ border-radius: 8px;
108
+ color: #a0a0c0;
109
+ font-size: 0.8rem;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ transition: all 0.2s;
113
+ width: auto;
114
+ }
115
+ .btn-small:hover { border-color: #7c3aed; color: #a78bfa; opacity: 1; }
116
  .status { font-size: 0.8rem; color: #555570; text-align: center; min-height: 1em; }
117
  .status.error { color: #ef4444; }
118
  .status.success { color: #22c55e; }
119
  .preview { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }
120
  .preview img { max-width: 160px; border-radius: 8px; border: 1px solid #222238; image-rendering: pixelated; }
121
  .download { font-size: 0.8rem; color: #a78bfa; cursor: pointer; text-decoration: underline; }
122
+ .size-tag { font-size: 0.75rem; color: #444460; }
123
  .decoded-text {
124
  background: #080810;
125
  border: 1px solid #222238;
 
129
  color: #e0e0f0;
130
  word-break: break-all;
131
  white-space: pre-wrap;
132
+ max-height: 200px;
133
+ overflow-y: auto;
134
  display: none;
135
  }
136
  .decoded-image { display: none; flex-direction: column; align-items: center; gap: 0.5rem; }
137
  .decoded-image img { max-width: 100%; border-radius: 8px; border: 1px solid #222238; }
138
+ .html-preview {
139
+ display: none;
140
+ flex-direction: column;
141
+ gap: 0.5rem;
142
+ }
143
+ .html-preview iframe {
144
+ width: 100%;
145
+ height: 300px;
146
+ border-radius: 8px;
147
+ border: 1px solid #222238;
148
+ background: white;
149
+ }
150
+ .code-preview {
151
+ display: none;
152
+ flex-direction: column;
153
+ gap: 0.5rem;
154
+ }
155
+ .code-preview pre {
156
+ background: #080810;
157
+ border: 1px solid #222238;
158
+ border-radius: 8px;
159
+ padding: 0.75rem;
160
+ font-size: 0.8rem;
161
+ color: #a78bfa;
162
+ overflow-x: auto;
163
+ max-height: 200px;
164
+ white-space: pre-wrap;
165
+ }
166
+ .lang-badge {
167
+ font-size: 0.7rem;
168
+ padding: 0.2rem 0.5rem;
169
+ border-radius: 4px;
170
+ background: #1a0a2e;
171
+ color: #a78bfa;
172
+ border: 1px solid #7c3aed;
173
+ align-self: flex-start;
174
+ }
175
+ .pdf-preview { display: none; flex-direction: column; gap: 0.5rem; font-size: 0.85rem; color: #a0a0c0; text-align: center; }
176
  </style>
177
  </head>
178
  <body>
 
184
  <h2>Encode</h2>
185
  <div class="tabs">
186
  <div class="tab active" onclick="switchTab('text')">Text</div>
187
+ <div class="tab" onclick="switchTab('file')">Image / PDF</div>
188
  </div>
189
 
190
  <div class="panel active" id="panel-text">
191
+ <textarea id="encodeInput" placeholder="Type a message, HTML, JS, Python..."></textarea>
192
  </div>
193
 
194
+ <div class="panel" id="panel-file">
195
+ <div class="upload-zone" id="uploadZone" onclick="document.getElementById('fileUpload').click()">
196
+ <input type="file" id="fileUpload" accept="image/*,.pdf" onchange="handleFileUpload(this)">
197
+ <span id="uploadLabel">Click to upload image or PDF (max 5MB)</span>
198
  </div>
199
  </div>
200
 
 
211
  </div>
212
  <button id="decodeBtn" onclick="decodeImage()">Extract</button>
213
  <div class="status" id="decodeStatus"></div>
214
+
215
  <div class="decoded-text" id="decodedText"></div>
216
+
217
+ <div class="html-preview" id="htmlPreview">
218
+ <span class="lang-badge">HTML</span>
219
+ <iframe id="htmlFrame" sandbox="allow-scripts"></iframe>
220
+ <div class="btn-row">
221
+ <button class="btn-small" onclick="downloadDecoded('decoded.txt')">Download .txt</button>
222
+ <button class="btn-small" onclick="downloadDecoded('decoded.html')">Download .html</button>
223
+ </div>
224
+ </div>
225
+
226
+ <div class="code-preview" id="jsPreview">
227
+ <span class="lang-badge">JavaScript</span>
228
+ <pre id="jsCode"></pre>
229
+ <div class="btn-row">
230
+ <button class="btn-small" onclick="downloadDecoded('decoded.txt')">Download .txt</button>
231
+ <button class="btn-small" onclick="downloadDecoded('decoded.js')">Download .js</button>
232
+ </div>
233
+ </div>
234
+
235
+ <div class="code-preview" id="pyPreview">
236
+ <span class="lang-badge">Python</span>
237
+ <pre id="pyCode"></pre>
238
+ <div class="btn-row">
239
+ <button class="btn-small" onclick="downloadDecoded('decoded.txt')">Download .txt</button>
240
+ <button class="btn-small" onclick="downloadDecoded('decoded.py')">Download .py</button>
241
+ </div>
242
+ </div>
243
+
244
  <div class="decoded-image" id="decodedImage">
245
  <img id="decodedImg" src="" alt="decoded">
246
+ <span class="download" onclick="downloadBinary('decoded.png')">Download Image</span>
247
+ </div>
248
+
249
+ <div class="pdf-preview" id="pdfPreview">
250
+ <span class="lang-badge">PDF</span>
251
+ <p>PDF extracted successfully.</p>
252
+ <button class="btn-small" onclick="downloadBinary('decoded.pdf')">Download PDF</button>
253
  </div>
254
  </div>
255
  </div>
256
 
257
  <script>
258
  let activeTab = "text";
259
+ let uploadedFile = null;
260
+ let decodedBinaryData = null;
261
+ let decodedBinaryMime = null;
262
+ let decodedTextContent = null;
263
  let encodedSrc = null;
264
 
265
  function switchTab(tab) {
266
  activeTab = tab;
267
  document.querySelectorAll(".tab").forEach((t, i) => {
268
+ t.classList.toggle("active", (i === 0 && tab === "text") || (i === 1 && tab === "file"));
269
  });
270
  document.getElementById("panel-text").classList.toggle("active", tab === "text");
271
+ document.getElementById("panel-file").classList.toggle("active", tab === "file");
272
  document.getElementById("encodeStatus").textContent = "";
273
  document.getElementById("encodePreview").innerHTML = "";
274
  }
275
 
276
+ function handleFileUpload(input) {
277
  const file = input.files[0];
278
  const zone = document.getElementById("uploadZone");
279
  const label = document.getElementById("uploadLabel");
280
  if (!file) return;
281
+ if (file.size > 5 * 1024 * 1024) {
282
  zone.className = "upload-zone has-error";
283
+ label.textContent = `Too large: ${(file.size/1024/1024).toFixed(2)}MB. Max is 5MB.`;
284
+ uploadedFile = null;
285
  return;
286
  }
287
+ uploadedFile = file;
288
  zone.className = "upload-zone has-file";
289
+ label.textContent = `${file.name} (${(file.size/1024).toFixed(1)}KB)`;
290
  }
291
 
292
  function handleDecodeUpload(input) {
293
  const file = input.files[0];
294
+ if (file) document.getElementById("decodeLabel").textContent = file.name;
 
295
  }
296
 
297
  async function encode() {
 
313
  });
314
  const data = await res.json();
315
  if (data.image) {
316
+ showEncodedResult(data.image, data.size);
317
  status.className = "status success";
318
+ status.textContent = "Encoded!";
319
  } else {
320
  status.className = "status error";
321
  status.textContent = "Error: " + (data.error || "Unknown");
322
  }
323
  } else {
324
+ if (!uploadedFile) { status.textContent = "Upload a file first."; btn.disabled = false; return; }
325
  status.textContent = "Encoding...";
326
  const form = new FormData();
327
+ form.append("file", uploadedFile);
328
+ const res = await fetch("/encode/file", { method: "POST", body: form });
329
  const data = await res.json();
330
  if (data.image) {
331
+ showEncodedResult(data.image, data.size);
332
  status.className = "status success";
333
+ status.textContent = "Encoded!";
334
  } else {
335
  status.className = "status error";
336
  status.textContent = "Error: " + (data.error || "Unknown");
 
339
  btn.disabled = false;
340
  }
341
 
342
+ function showEncodedResult(b64, size) {
343
  encodedSrc = "data:image/png;base64," + b64;
344
  const preview = document.getElementById("encodePreview");
345
  const img = document.createElement("img");
 
348
  dl.className = "download";
349
  dl.textContent = "Download ChromaCode PNG";
350
  dl.onclick = () => { const a = document.createElement("a"); a.href = encodedSrc; a.download = "chromacode.png"; a.click(); };
351
+ const sz = document.createElement("span");
352
+ sz.className = "size-tag";
353
+ sz.textContent = `Canvas: ${size} px`;
354
  preview.appendChild(img);
355
  preview.appendChild(dl);
356
+ preview.appendChild(sz);
357
+ }
358
+
359
+ function detectTextType(text) {
360
+ const t = text.trim();
361
+ if (/^[\s\S]*<html[\s\S]*>[\s\S]*<\/html>/i.test(t) || /^<!DOCTYPE html/i.test(t) || (/<[a-z][\s\S]*>/i.test(t) && /<\/[a-z]+>/i.test(t))) return "html";
362
+ if (/^(import |from |def |class |if __name__|print\(|#!\/usr\/bin\/env python)/m.test(t)) return "python";
363
+ if (/^(const |let |var |function |class |import |export |=>|\/\/|console\.log)/m.test(t)) return "js";
364
+ return "text";
365
+ }
366
+
367
+ function hideAllOutputs() {
368
+ ["decodedText","htmlPreview","jsPreview","pyPreview","decodedImage","pdfPreview"].forEach(id => {
369
+ const el = document.getElementById(id);
370
+ el.style.display = "none";
371
+ });
372
  }
373
 
374
  async function decodeImage() {
375
  const file = document.getElementById("decodeFile").files[0];
376
  if (!file) return;
377
  const status = document.getElementById("decodeStatus");
 
 
378
  const btn = document.getElementById("decodeBtn");
379
+ hideAllOutputs();
380
  status.className = "status";
 
 
381
  btn.disabled = true;
382
  status.textContent = "Extracting...";
383
 
 
387
  const data = await res.json();
388
 
389
  if (data.type === "text") {
390
+ const text = data.text;
391
+ decodedTextContent = text;
392
+ const kind = detectTextType(text);
393
+
394
+ if (kind === "html") {
395
+ const frame = document.getElementById("htmlFrame");
396
+ frame.srcdoc = text;
397
+ document.getElementById("htmlPreview").style.display = "flex";
398
+ status.className = "status success";
399
+ status.textContent = "HTML detected — previewing below.";
400
+ } else if (kind === "js") {
401
+ document.getElementById("jsCode").textContent = text;
402
+ document.getElementById("jsPreview").style.display = "flex";
403
+ status.className = "status success";
404
+ status.textContent = "JavaScript detected.";
405
+ } else if (kind === "python") {
406
+ document.getElementById("pyCode").textContent = text;
407
+ document.getElementById("pyPreview").style.display = "flex";
408
+ status.className = "status success";
409
+ status.textContent = "Python detected.";
410
+ } else {
411
+ const out = document.getElementById("decodedText");
412
+ out.textContent = text;
413
+ out.style.display = "block";
414
+ status.className = "status success";
415
+ status.textContent = "Text extracted!";
416
+ }
417
  } else if (data.type === "image") {
418
+ const src = "data:image/png;base64," + data.image;
419
+ decodedBinaryData = data.image;
420
+ decodedBinaryMime = "image/png";
421
+ document.getElementById("decodedImg").src = src;
422
+ document.getElementById("decodedImage").style.display = "flex";
423
  status.className = "status success";
424
  status.textContent = "Image extracted!";
425
+ } else if (data.type === "pdf") {
426
+ decodedBinaryData = data.pdf;
427
+ decodedBinaryMime = "application/pdf";
428
+ document.getElementById("pdfPreview").style.display = "flex";
429
+ status.className = "status success";
430
+ status.textContent = "PDF extracted!";
431
  } else {
432
  status.className = "status error";
433
  status.textContent = "Error: " + (data.error || "Unknown");
 
435
  btn.disabled = false;
436
  }
437
 
438
+ function downloadDecoded(filename) {
439
+ const blob = new Blob([decodedTextContent], { type: "text/plain" });
440
+ const a = document.createElement("a");
441
+ a.href = URL.createObjectURL(blob);
442
+ a.download = filename;
443
+ a.click();
444
+ }
445
+
446
+ function downloadBinary(filename) {
447
+ const bytes = atob(decodedBinaryData);
448
+ const arr = new Uint8Array(bytes.length);
449
+ for (let i = 0; i < bytes.length; i++) arr[i] = bytes.charCodeAt(i);
450
+ const blob = new Blob([arr], { type: decodedBinaryMime });
451
  const a = document.createElement("a");
452
+ a.href = URL.createObjectURL(blob);
453
+ a.download = filename;
454
  a.click();
455
  }
456
  </script>
457
  </body>
458
+ </html>