| 520 | } |
| 521 | |
| 522 | function extractProgressCard() { |
| 523 | const j = state.extractJob; |
| 524 | if (!j) return ""; |
| 525 | const pct = Math.round((j.progress || 0) * 100); |
| 526 | const failed = j.status === "error"; |
| 527 | const cancelled = j.status === "cancelled"; |
| 528 | const done = j.status === "done"; |
| 529 | const line = failed ? "Failed" : cancelled ? "Cancelled" : done ? "Done" : `${j.stage || j.status}…`; |
| 530 | return `<div class="eyebrow">IN PROGRESS</div> |
| 531 | <div class="progress-card"> |
| 532 | <div class="progress-top"> |
| 533 | <div class="progress-art"></div> |
| 534 | <div style="flex:1;min-width:0"> |
| 535 | <div style="font-size:14px;font-weight:600;color:#eaeaec;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(j.title || "Track")}</div> |
| 536 | <div style="font-size:12px;color:${failed ? "#f0506e" : "#7a7a82"};margin-top:1px">${esc(line)}</div> |
| 537 | </div> |
| 538 | <span class="progress-pct">${done ? "100" : pct}%</span> |
| 539 | </div> |
| 540 | <div class="progress-bar"><i style="width:${done ? 100 : pct}%"></i></div> |
| 541 | </div>`; |
| 542 | } |
| 543 | |
| 544 | function extractScreen() { |
| 545 | const fileName = state.extractFile?.name; |