Spaces:
Sleeping
Sleeping
File size: 2,597 Bytes
f65e025 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | "use client";
import { Check, Loader2 } from "lucide-react";
import type { DocumentDetail } from "@/lib/types";
/**
* A slim live stepper that reflects pipeline progress by inspecting which
* parts of the document detail have been populated. Renders only while the
* document is still processing.
*/
export default function ProcessingBar({ detail }: { detail: DocumentDetail }) {
if (detail.status === "ready" || detail.status === "failed") return null;
const steps = [
{ label: "Parsing", done: (detail.pages?.length ?? 0) > 0 },
{ label: "Classifying", done: !!detail.classification },
{ label: "Extracting", done: !!detail.extraction },
{ label: "Summarizing", done: !!detail.summary },
];
const activeIdx = steps.findIndex((s) => !s.done);
return (
<div className="border-b border-white/[0.06] bg-surface-900/50 px-4 py-2.5">
<div className="flex items-center gap-2">
{steps.map((s, i) => {
const active = i === activeIdx;
return (
<div key={s.label} className="flex flex-1 items-center gap-2">
<div className="flex items-center gap-1.5">
<span
className={`flex h-4 w-4 items-center justify-center rounded-full text-[9px] ${
s.done
? "bg-emerald-500/20 text-emerald-400"
: active
? "bg-brand-500/20 text-brand-300"
: "bg-white/[0.05] text-white/30"
}`}
>
{s.done ? (
<Check size={10} />
) : active ? (
<Loader2 size={10} className="animate-spin" />
) : (
i + 1
)}
</span>
<span
className={`text-[11px] font-medium ${
s.done
? "text-white/60"
: active
? "text-brand-200"
: "text-white/30"
}`}
>
{s.label}
</span>
</div>
{i < steps.length - 1 && (
<div className="h-px flex-1 bg-white/[0.07]">
<div
className={`h-px transition-all duration-500 ${
s.done ? "w-full bg-emerald-500/40" : "w-0"
}`}
/>
</div>
)}
</div>
);
})}
</div>
</div>
);
}
|