diff options
| author | kj_sh604 | 2026-02-14 00:16:21 -0500 |
|---|---|---|
| committer | kj_sh604 | 2026-02-14 00:16:21 -0500 |
| commit | 5d527cb99cd733f02db25ac4666e817699a8a5a0 (patch) | |
| tree | f03af296a449e2f3aee372c0d20edd979e0e64a5 /demoware | |
| parent | d44a2f72e988d423a7ad6531f6779aff82edc848 (diff) | |
refactor: minify inline css and js
might regret this, but I probably won't iterate on the demoware on the public repo
Diffstat (limited to 'demoware')
| -rw-r--r-- | demoware/index.html | 249 |
1 files changed, 2 insertions, 247 deletions
diff --git a/demoware/index.html b/demoware/index.html index 95c6847..ce93e4e 100644 --- a/demoware/index.html +++ b/demoware/index.html @@ -6,49 +6,7 @@ <title>slide merging demoware</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.min.css"> <style> - .file-item { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.3rem 0; - } - .file-item button { - padding: 0.15rem 0.5rem; - margin: 0; - font-size: 0.85rem; - min-width: 2rem; - } - .file-item .fname { - flex: 1; - font-family: var(--font-family, monospace); - } - #drop-zone { - border: 2px dashed #555; - padding: 2rem; - text-align: center; - border-radius: 6px; - margin: 1rem 0; - cursor: pointer; - transition: border-color 0.15s, background 0.15s; - } - #drop-zone.over { - border-color: #7ec8e3; - background: rgba(126, 200, 227, 0.06); - } - #command-display { - white-space: pre-wrap; - word-break: break-all; - } - .hidden { display: none !important; } - .running { color: #ff9800; } - .done { color: #4caf50; } - .error { color: #f44336; } - #log-output { - max-height: 300px; - overflow-y: auto; - font-size: 0.85rem; - } - footer { margin-top: 2rem; } + .file-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; } .file-item button { padding: 0.15rem 0.5rem; margin: 0; font-size: 0.85rem; min-width: 2rem; } .file-item .fname { flex: 1; font-family: var(--font-family, monospace); } #drop-zone { border: 2px dashed #555; padding: 2rem; text-align: center; border-radius: 6px; margin: 1rem 0; cursor: pointer; transition: border-color 0.15s, background 0.15s; } #drop-zone.over { border-color: #7ec8e3; background: rgba(126, 200, 227, 0.06); } #command-display { white-space: pre-wrap; word-break: break-all; } .hidden { display: none !important; } .running { color: #ff9800; } .done { color: #4caf50; } .error { color: #f44336; } #log-output { max-height: 300px; overflow-y: auto; font-size: 0.85rem; } footer { margin-top: 2rem; } </style> </head> <body> @@ -88,210 +46,7 @@ </footer> <script> - (() => { - 'use strict'; - - // -- state -- - let files = []; // {id, name, file} - let nextId = 1; - let busy = false; - - // -- dom refs -- - const dropZone = document.getElementById('drop-zone'); - const fileInput = document.getElementById('file-input'); - const fileList = document.getElementById('file-list'); - const emptyMsg = document.getElementById('empty-msg'); - const mergeBtn = document.getElementById('merge-btn'); - const cmdSec = document.getElementById('cmd-section'); - const cmdPre = document.getElementById('command-display'); - const statusSec = document.getElementById('status-section'); - const statusMsg = document.getElementById('status-msg'); - const logPre = document.getElementById('log-output'); - const dlSec = document.getElementById('dl-section'); - const dlLink = document.getElementById('dl-link'); - - // -- file input -- - fileInput.addEventListener('change', () => { - addFiles(fileInput.files); - fileInput.value = ''; - }); - - // -- drag & drop -- - dropZone.addEventListener('dragover', e => { - e.preventDefault(); - dropZone.classList.add('over'); - }); - dropZone.addEventListener('dragleave', () => dropZone.classList.remove('over')); - dropZone.addEventListener('drop', e => { - e.preventDefault(); - dropZone.classList.remove('over'); - addFiles(e.dataTransfer.files); - }); - dropZone.addEventListener('click', () => fileInput.click()); - - // -- list management -- - - function addFiles(rawFiles) { - for (const f of rawFiles) { - if (!f.name.toLowerCase().endsWith('.pptx')) continue; - files.push({ id: nextId++, name: f.name, file: f }); - } - render(); - } - - function render() { - fileList.innerHTML = ''; - - if (files.length === 0) { - emptyMsg.classList.remove('hidden'); - mergeBtn.disabled = true; - return; - } - - emptyMsg.classList.add('hidden'); - mergeBtn.disabled = busy; - - files.forEach((item, i) => { - const row = document.createElement('div'); - row.className = 'file-item'; - - const up = mkbtn('▲', i === 0, () => swap(i, i - 1)); - const dn = mkbtn('▼', i === files.length - 1, () => swap(i, i + 1)); - const rm = mkbtn('✕', false, () => { files.splice(i, 1); render(); }); - - const span = document.createElement('span'); - span.className = 'fname'; - span.textContent = (i + 1) + '. ' + item.name; - - row.append(up, dn, rm, span); - fileList.appendChild(row); - }); - } - - function mkbtn(label, disabled, onclick) { - const b = document.createElement('button'); - b.textContent = label; - b.disabled = disabled; - b.onclick = onclick; - return b; - } - - function swap(a, b) { - [files[a], files[b]] = [files[b], files[a]]; - render(); - } - - // -- merge flow -- - - mergeBtn.addEventListener('click', async () => { - if (files.length === 0 || busy) return; - busy = true; - mergeBtn.disabled = true; - - // reset ui sections - cmdSec.classList.add('hidden'); - statusSec.classList.add('hidden'); - dlSec.classList.add('hidden'); - logPre.textContent = ''; - logPre.classList.add('hidden'); - - const jobId = Date.now() + '_' + rnd(); - - statusSec.classList.remove('hidden'); - - // 1. upload each file - for (let i = 0; i < files.length; i++) { - const item = files[i]; - statusMsg.textContent = 'uploading ' + (i + 1) + '/' + files.length + ': ' + item.name; - statusMsg.className = 'running'; - - const serverName = item.id + '_' + item.name; - try { - const res = await fetch('/api/upload', { - method: 'POST', - headers: { - 'X-Job-Id': jobId, - 'X-Filename': encodeURIComponent(serverName), - }, - body: item.file, - }); - if (!res.ok) { - const err = await res.json().catch(() => ({ error: 'upload failed' })); - throw new Error(err.error); - } - } catch (e) { - statusMsg.textContent = 'upload error: ' + e.message; - statusMsg.className = 'error'; - busy = false; - mergeBtn.disabled = false; - return; - } - } - - // 2. send merge request - statusMsg.textContent = 'starting merge...'; - const serverFiles = files.map(f => f.id + '_' + f.name); - - let mergeData; - try { - const res = await fetch('/api/merge', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ job_id: jobId, files: serverFiles }), - }); - mergeData = await res.json(); - if (!res.ok) throw new Error(mergeData.error || 'merge failed'); - } catch (e) { - statusMsg.textContent = 'merge error: ' + e.message; - statusMsg.className = 'error'; - busy = false; - mergeBtn.disabled = false; - return; - } - - // 3. show the command - cmdSec.classList.remove('hidden'); - cmdPre.textContent = '$ ' + mergeData.command; - - // 4. poll for completion - statusMsg.textContent = 'merging... this may take a while depending on slide count.'; - - const poll = setInterval(async () => { - try { - const res = await fetch('/api/status/' + jobId); - const s = await res.json(); - - if (s.log) { - logPre.classList.remove('hidden'); - logPre.textContent = s.log; - } - - if (s.status === 'done') { - clearInterval(poll); - statusMsg.textContent = 'merge complete!'; - statusMsg.className = 'done'; - dlSec.classList.remove('hidden'); - dlLink.href = '/output/' + mergeData.output; - dlLink.download = mergeData.output; - busy = false; - mergeBtn.disabled = false; - } else if (s.status === 'error') { - clearInterval(poll); - statusMsg.textContent = 'merge failed — check the log below.'; - statusMsg.className = 'error'; - busy = false; - mergeBtn.disabled = false; - } - } catch (_) { - // network hiccup, keep polling - } - }, 2000); - }); - - function rnd() { - return Math.random().toString(36).substring(2, 10); - } - })(); +(()=>{"use strict";let e=[],t=1,n=!1;const d=document.getElementById("drop-zone"),a=document.getElementById("file-input"),o=document.getElementById("file-list"),s=document.getElementById("empty-msg"),i=document.getElementById("merge-btn"),r=document.getElementById("cmd-section"),l=document.getElementById("command-display"),c=document.getElementById("status-section"),m=document.getElementById("status-msg"),u=document.getElementById("log-output"),g=document.getElementById("dl-section"),h=document.getElementById("dl-link");function p(n){for(const d of n)d.name.toLowerCase().endsWith(".pptx")&&e.push({id:t++,name:d.name,file:d});f()}function f(){if(o.innerHTML="",0===e.length)return s.classList.remove("hidden"),void(i.disabled=!0);s.classList.add("hidden"),i.disabled=n,e.forEach(((t,n)=>{const d=document.createElement("div");d.className="file-item";const a=v("▲",0===n,(()=>y(n,n-1))),s=v("▼",n===e.length-1,(()=>y(n,n+1))),i=v("✕",!1,(()=>{e.splice(n,1),f()})),r=document.createElement("span");r.className="fname",r.textContent=n+1+". "+t.name,d.append(a,s,i,r),o.appendChild(d)}))}function v(e,t,n){const d=document.createElement("button");return d.textContent=e,d.disabled=t,d.onclick=n,d}function y(t,n){[e[t],e[n]]=[e[n],e[t]],f()}a.addEventListener("change",(()=>{p(a.files),a.value=""})),d.addEventListener("dragover",(e=>{e.preventDefault(),d.classList.add("over")})),d.addEventListener("dragleave",(()=>d.classList.remove("over"))),d.addEventListener("drop",(e=>{e.preventDefault(),d.classList.remove("over"),p(e.dataTransfer.files)})),d.addEventListener("click",(()=>a.click())),i.addEventListener("click",(async()=>{if(0===e.length||n)return;n=!0,i.disabled=!0,r.classList.add("hidden"),c.classList.add("hidden"),g.classList.add("hidden"),u.textContent="",u.classList.add("hidden");const t=Date.now()+"_"+Math.random().toString(36).substring(2,10);c.classList.remove("hidden");for(let d=0;d<e.length;d++){const a=e[d];m.textContent="uploading "+(d+1)+"/"+e.length+": "+a.name,m.className="running";const o=a.id+"_"+a.name;try{const e=await fetch("/api/upload",{method:"POST",headers:{"X-Job-Id":t,"X-Filename":encodeURIComponent(o)},body:a.file});if(!e.ok){const t=await e.json().catch((()=>({error:"upload failed"})));throw new Error(t.error)}}catch(e){return m.textContent="upload error: "+e.message,m.className="error",n=!1,void(i.disabled=!1)}}m.textContent="starting merge...";const d=e.map((e=>e.id+"_"+e.name));let a;try{const e=await fetch("/api/merge",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({job_id:t,files:d})});if(a=await e.json(),!e.ok)throw new Error(a.error||"merge failed")}catch(e){return m.textContent="merge error: "+e.message,m.className="error",n=!1,void(i.disabled=!1)}r.classList.remove("hidden"),l.textContent="$ "+a.command,m.textContent="merging... this may take a while depending on slide count.";const o=setInterval((async()=>{try{const e=await fetch("/api/status/"+t),d=await e.json();d.log&&(u.classList.remove("hidden"),u.textContent=d.log),"done"===d.status?(clearInterval(o),m.textContent="merge complete!",m.className="done",g.classList.remove("hidden"),h.href="/output/"+a.output,h.download=a.output,n=!1,i.disabled=!1):"error"===d.status&&(clearInterval(o),m.textContent="merge failed — check the log below.",m.className="error",n=!1,i.disabled=!1)}catch(e){}}),2e3)}))})(); </script> </body> </html> |
