Reaperxxxx commited on
Commit
4bb3643
Β·
verified Β·
1 Parent(s): 4e89500

Update public/index.html

Browse files
Files changed (1) hide show
  1. public/index.html +18 -117
public/index.html CHANGED
@@ -152,13 +152,8 @@
152
  .tool-badge.missing { background: rgba(255,68,85,0.1); color: var(--danger); border: 1px solid rgba(255,68,85,0.3); }
153
 
154
  /* URL UPLOAD */
155
- .url-upload-wrap { margin-top: 12px; }
156
- .url-upload-inner { display: flex; align-items: center; gap: 10px; background: var(--panel); border: 1px solid var(--border); border-radius: 4px; padding: 10px 14px; }
157
- .url-label { font-family: 'Share Tech Mono', monospace; font-size: 11px; color: var(--text-dim); letter-spacing: 1px; white-space: nowrap; }
158
- .url-input { flex: 1; background: var(--bg); border: 1px solid var(--border-bright); color: var(--text-bright); font-family: 'Share Tech Mono', monospace; font-size: 12px; padding: 7px 10px; border-radius: 3px; outline: none; transition: border-color 0.2s; }
159
- .url-input:focus { border-color: var(--accent); }
160
- .url-input::placeholder { color: var(--text-dim); }
161
- .url-btn { padding: 7px 16px; font-size: 12px; white-space: nowrap; }
162
 
163
  /* TOAST */
164
  .toast { position: fixed; bottom: 30px; right: 30px; background: var(--panel); border: 1px solid var(--accent); color: var(--text-bright); padding: 12px 20px; border-radius: 4px; font-size: 14px; font-weight: 600; letter-spacing: 1px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); transform: translateY(80px); opacity: 0; transition: all 0.3s cubic-bezier(0.34,1.56,0.64,1); z-index: 1000; }
@@ -184,7 +179,7 @@
184
 
185
  <!-- Steps -->
186
  <div class="steps">
187
- <div class="step active" id="step1"><span class="step-num">01</span> Upload APK</div>
188
  <div class="step" id="step2"><span class="step-num">02</span> Edit Characters</div>
189
  <div class="step" id="step3"><span class="step-num">03</span> Export Patched APK</div>
190
  </div>
@@ -192,22 +187,6 @@
192
  <!-- Tool status -->
193
  <div class="tool-status" id="toolStatus"></div>
194
 
195
- <!-- Upload -->
196
- <div class="upload-zone" id="uploadZone">
197
- <div class="upload-icon">πŸ“¦</div>
198
- <div class="upload-title">Drop SuperCity.apk here</div>
199
- <div class="upload-sub">or click to browse Β· .apk files only Β· max 200 MB</div>
200
- <input type="file" id="apkInput" accept=".apk">
201
- </div>
202
- <!-- URL Upload -->
203
- <div class="url-upload-wrap" id="urlUploadWrap">
204
- <div class="url-upload-inner">
205
- <span class="url-label">or load from URL</span>
206
- <input class="url-input" type="text" id="apkUrlInput" placeholder="https://example.com/SuperCity.apk">
207
- <button class="btn btn-secondary url-btn" onclick="uploadFromUrl()">⬇ Load URL</button>
208
- </div>
209
- </div>
210
-
211
  <div class="progress-wrap" id="progressWrap">
212
  <div class="progress-label" id="progressLabel">Uploading…</div>
213
  <div class="progress-bar-outer"><div class="progress-bar-inner" id="progressBar"></div></div>
@@ -336,114 +315,36 @@ fetch('/tools').then(r => r.json()).then(tools => {
336
  }
337
  }).catch(() => {});
338
 
339
- // ── UPLOAD ─────────────────────────────────────────────────────────
340
- const uploadZone = document.getElementById('uploadZone');
341
- const apkInput = document.getElementById('apkInput');
342
-
343
- uploadZone.addEventListener('click', () => apkInput.click());
344
- uploadZone.addEventListener('dragover', e => { e.preventDefault(); uploadZone.classList.add('drag-over'); });
345
- uploadZone.addEventListener('dragleave', () => uploadZone.classList.remove('drag-over'));
346
- uploadZone.addEventListener('drop', e => { e.preventDefault(); uploadZone.classList.remove('drag-over'); if (e.dataTransfer.files[0]) uploadAPK(e.dataTransfer.files[0]); });
347
- apkInput.addEventListener('change', () => { if (apkInput.files[0]) uploadAPK(apkInput.files[0]); });
348
-
349
- function uploadAPK(file) {
350
- if (!file.name.endsWith('.apk')) { showToast('Only .apk files', true); return; }
351
-
352
  const wrap = document.getElementById('progressWrap');
353
  const bar = document.getElementById('progressBar');
354
  const label = document.getElementById('progressLabel');
355
  wrap.style.display = 'block';
356
- bar.style.width = '0%';
357
- label.textContent = 'Uploading…';
358
-
359
- const form = new FormData();
360
- form.append('apk', file);
361
 
362
- const xhr = new XMLHttpRequest();
363
- xhr.open('POST', '/upload');
364
-
365
- xhr.upload.onprogress = e => {
366
- if (e.lengthComputable) {
367
- const pct = Math.round(e.loaded / e.total * 80);
368
- bar.style.width = pct + '%';
369
- label.textContent = `Uploading… ${pct}%`;
370
- }
371
- };
372
-
373
- xhr.onload = () => {
374
- bar.style.width = '100%';
375
- label.textContent = 'Parsing characters…';
376
- if (xhr.status === 200) {
377
- const data = JSON.parse(xhr.responseText);
378
  sessionToken = data.token;
379
  originalRaw = data.characters;
380
  parseCharacters(data.characters);
381
  wrap.style.display = 'none';
382
  document.getElementById('fileInfoBar').style.display = 'flex';
383
  document.getElementById('fileInfoBar').innerHTML = `
384
- <div class="file-info">πŸ“¦ <span class="file-info-name">${file.name}</span>
385
- &nbsp;Β·&nbsp; ${characters.length} characters loaded &nbsp;Β·&nbsp; session: ${sessionToken.split('_')[0]}</div>`;
386
  document.getElementById('editorLayout').style.display = 'grid';
387
- document.getElementById('urlUploadWrap').style.display = 'none';
388
  setStep(2);
389
  showToast(`βœ” Loaded ${characters.length} characters`);
390
- } else {
 
391
  wrap.style.display = 'none';
392
- const err = JSON.parse(xhr.responseText);
393
- showToast('Error: ' + err.error, true);
394
- }
395
- };
396
-
397
- xhr.onerror = () => { wrap.style.display = 'none'; showToast('Upload failed', true); };
398
- xhr.send(form);
399
- }
400
-
401
- function uploadFromUrl() {
402
- const url = document.getElementById('apkUrlInput').value.trim();
403
- if (!url) { showToast('Enter a URL first', true); return; }
404
- if (!url.toLowerCase().endsWith('.apk')) { showToast('URL must point to a .apk file', true); return; }
405
-
406
- const wrap = document.getElementById('progressWrap');
407
- const bar = document.getElementById('progressBar');
408
- const label = document.getElementById('progressLabel');
409
- wrap.style.display = 'block';
410
- bar.style.width = '10%';
411
- label.textContent = 'Fetching APK from URL…';
412
-
413
- fetch('/upload-url', {
414
- method: 'POST',
415
- headers: { 'Content-Type': 'application/json' },
416
- body: JSON.stringify({ url }),
417
- })
418
- .then(res => {
419
- bar.style.width = '80%';
420
- label.textContent = 'Parsing characters…';
421
- if (!res.ok) return res.json().then(e => { throw new Error(e.error); });
422
- return res.json();
423
- })
424
- .then(data => {
425
- bar.style.width = '100%';
426
- sessionToken = data.token;
427
- originalRaw = data.characters;
428
- parseCharacters(data.characters);
429
- wrap.style.display = 'none';
430
- const fname = url.split('/').pop();
431
- document.getElementById('fileInfoBar').style.display = 'flex';
432
- document.getElementById('fileInfoBar').innerHTML = `
433
- <div class="file-info">🌐 <span class="file-info-name">${fname}</span>
434
- &nbsp;Β·&nbsp; ${characters.length} characters loaded &nbsp;Β·&nbsp; session: ${sessionToken.split('_')[0]}</div>`;
435
- document.getElementById('editorLayout').style.display = 'grid';
436
- document.getElementById('urlUploadWrap').style.display = 'none';
437
- document.getElementById('uploadZone').style.display = 'none';
438
- setStep(2);
439
- showToast(`βœ” Loaded ${characters.length} characters from URL`);
440
- })
441
- .catch(err => {
442
- wrap.style.display = 'none';
443
- bar.style.width = '0%';
444
- showToast('Error: ' + err.message, true);
445
- });
446
- }
447
 
448
  // ── PARSE ──────────────────────────────────────────────────────────
449
  function parseCharacters(raw) {
 
152
  .tool-badge.missing { background: rgba(255,68,85,0.1); color: var(--danger); border: 1px solid rgba(255,68,85,0.3); }
153
 
154
  /* URL UPLOAD */
155
+ .url-upload-wrap { display: none; }
156
+ .url-btn { display: none; }
 
 
 
 
 
157
 
158
  /* TOAST */
159
  .toast { position: fixed; bottom: 30px; right: 30px; background: var(--panel); border: 1px solid var(--accent); color: var(--text-bright); padding: 12px 20px; border-radius: 4px; font-size: 14px; font-weight: 600; letter-spacing: 1px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); transform: translateY(80px); opacity: 0; transition: all 0.3s cubic-bezier(0.34,1.56,0.64,1); z-index: 1000; }
 
179
 
180
  <!-- Steps -->
181
  <div class="steps">
182
+ <div class="step active" id="step1"><span class="step-num">01</span> Load APK</div>
183
  <div class="step" id="step2"><span class="step-num">02</span> Edit Characters</div>
184
  <div class="step" id="step3"><span class="step-num">03</span> Export Patched APK</div>
185
  </div>
 
187
  <!-- Tool status -->
188
  <div class="tool-status" id="toolStatus"></div>
189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  <div class="progress-wrap" id="progressWrap">
191
  <div class="progress-label" id="progressLabel">Uploading…</div>
192
  <div class="progress-bar-outer"><div class="progress-bar-inner" id="progressBar"></div></div>
 
315
  }
316
  }).catch(() => {});
317
 
318
+ // ── AUTO-INIT ──────────────────────────────────────────────────────
319
+ (function initFromServer() {
 
 
 
 
 
 
 
 
 
 
 
320
  const wrap = document.getElementById('progressWrap');
321
  const bar = document.getElementById('progressBar');
322
  const label = document.getElementById('progressLabel');
323
  wrap.style.display = 'block';
324
+ bar.style.width = '30%';
325
+ label.textContent = 'Loading APK…';
 
 
 
326
 
327
+ fetch('/init')
328
+ .then(r => { if (!r.ok) return r.json().then(e => { throw new Error(e.error); }); return r.json(); })
329
+ .then(data => {
330
+ bar.style.width = '100%';
 
 
 
 
 
 
 
 
 
 
 
 
331
  sessionToken = data.token;
332
  originalRaw = data.characters;
333
  parseCharacters(data.characters);
334
  wrap.style.display = 'none';
335
  document.getElementById('fileInfoBar').style.display = 'flex';
336
  document.getElementById('fileInfoBar').innerHTML = `
337
+ <div class="file-info">πŸ“¦ <span class="file-info-name">super-city-2.010.64-mod-t-5play.apk</span>
338
+ &nbsp;Β·&nbsp; ${characters.length} characters loaded</div>`;
339
  document.getElementById('editorLayout').style.display = 'grid';
 
340
  setStep(2);
341
  showToast(`βœ” Loaded ${characters.length} characters`);
342
+ })
343
+ .catch(err => {
344
  wrap.style.display = 'none';
345
+ showToast('Failed to load APK: ' + err.message, true);
346
+ });
347
+ })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  // ── PARSE ──────────────────────────────────────────────────────────
350
  function parseCharacters(raw) {