promises, link

This commit is contained in:
2026-09-13 15:40:54 +05:30
parent 13c24e9db3
commit d8b42ece79
6 changed files with 315 additions and 110 deletions
+18 -31
View File
@@ -111,10 +111,11 @@ export function Editor() {
const [error, setError] = useState<string | null>(null);
const [status, setStatus] = useState<string | null>(null);
const [progress, setProgress] = useState<{
phase: "generate" | "zip" | "download";
phase: "generate" | "zip";
current: number;
total: number;
} | null>(null);
const [downloadHref, setDownloadHref] = useState<string | null>(null);
const [cursor, setCursor] = useState<"grab" | "grabbing" | "default">(
"default",
);
@@ -354,6 +355,7 @@ export function Editor() {
setBusy(true);
setError(null);
setStatus(null);
setDownloadHref(null);
setProgress({ phase: "generate", current: 0, total: config.count });
try {
@@ -390,23 +392,9 @@ export function Editor() {
}
});
setProgress({ phase: "download", current: 1, total: 1 });
const zipResponse = await fetch(`/api/download/${jobId}`);
if (!zipResponse.ok) {
throw new Error("Could not download the zip file");
}
const blob = await zipResponse.blob();
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "ids.zip";
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
setProgress(null);
setStatus(`Downloaded ids.zip with ${config.count} PNGs`);
setDownloadHref(`/api/download/${jobId}`);
setStatus(`${config.count} images are ready. Download the zip below.`);
} catch (err) {
setProgress(null);
setStatus(null);
@@ -766,6 +754,15 @@ export function Editor() {
{status}
</p>
) : null}
{downloadHref && !busy ? (
<a
href={downloadHref}
download="ids.zip"
className="rounded-xl bg-emerald-500 px-4 py-3 text-center text-sm font-semibold text-white transition hover:bg-emerald-400"
>
Download ids.zip
</a>
) : null}
<button
type="button"
@@ -785,7 +782,7 @@ export function Editor() {
function progressLabel(
progress: {
phase: "generate" | "zip" | "download";
phase: "generate" | "zip";
current: number;
total: number;
} | null,
@@ -795,9 +792,6 @@ function progressLabel(
if (progress.phase === "zip") {
return `Zipping ${progress.current} / ${progress.total}`;
}
if (progress.phase === "download") {
return "Downloading zip…";
}
return `Generating ${progress.current} / ${progress.total}`;
}
@@ -805,7 +799,7 @@ function ProgressPanel({
progress,
}: {
progress: {
phase: "generate" | "zip" | "download";
phase: "generate" | "zip";
current: number;
total: number;
};
@@ -814,21 +808,14 @@ function ProgressPanel({
progress.total > 0
? Math.min(100, Math.round((progress.current / progress.total) * 100))
: 0;
const title =
progress.phase === "zip"
? "Zipping"
: progress.phase === "download"
? "Downloading"
: "Generating";
const title = progress.phase === "zip" ? "Zipping" : "Generating";
return (
<div className="rounded-lg border border-indigo-900 bg-indigo-950/50 px-3 py-3 text-sm text-indigo-100">
<div className="flex items-center justify-between gap-3">
<span>{title}</span>
<span className="font-mono text-xs text-indigo-200">
{progress.phase === "download"
? "ids.zip"
: `${progress.current} / ${progress.total}`}
{progress.current} / {progress.total}
</span>
</div>
<div className="mt-2 h-2 overflow-hidden rounded-full bg-zinc-800">