File size: 2,052 Bytes
95a2dcc
 
 
 
 
 
 
 
 
 
 
 
 
 
14c6f28
95a2dcc
14c6f28
95a2dcc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14c6f28
 
 
95a2dcc
 
14c6f28
95a2dcc
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useProgress } from "@/lib/progress";

function fmt(s: number): string {
  const m = Math.floor(s / 60);
  const sec = Math.floor(s % 60);
  return `${m}:${sec.toString().padStart(2, "0")}`;
}

export default function ProgressBar() {
  const state = useProgress();
  if (state.phase === "idle") return null;

  if (state.phase === "error") {
    return (
      <div className="sticky top-0 z-40 border-b border-red-900/40 bg-red-950/80 backdrop-blur-md px-4 sm:px-8 py-2.5">
        <span className="label-mono text-red-400">progress error</span>
        <span className="ml-3 text-sm text-red-300/90 break-words">{state.message}</span>
      </div>
    );
  }

  const isRunning = state.phase === "running";
  const isDialog = isRunning && state.kind === "dialog";
  const fill =
    state.phase === "done"
      ? 1
      : isDialog && state.total > 0
      ? state.turn / state.total
      : null;

  const elapsedS = state.phase === "running" ? state.elapsedS : state.phase === "done" ? state.elapsedS : 0;
  const label =
    state.phase === "done"
      ? `done 路 ${fmt(elapsedS)}`
      : isDialog
      ? `Turn ${state.turn} of ${state.total}${fmt(elapsedS)}`
      : `Generating 路 ${fmt(elapsedS)}`;

  return (
    <div className="sticky top-0 z-40 border-b border-[hsl(var(--ember))]/30 bg-[hsl(var(--ember))]/15 backdrop-blur-md px-4 sm:px-8 py-2">
      <div className="flex items-center gap-3 sm:gap-4">
        <span className="label-mono text-[hsl(var(--ember))] whitespace-nowrap text-[10px] sm:text-[10.5px]">
          {label}
        </span>
        <div className="flex-1 min-w-0 h-1 bg-[hsl(var(--ember))]/20 rounded-sm overflow-hidden">
          {fill === null ? (
            <div className="h-full w-1/3 bg-[hsl(var(--ember))] animate-progress-stripe" />
          ) : (
            <div
              className="h-full bg-[hsl(var(--ember))] transition-[width] duration-200 ease-linear"
              style={{ width: `${fill * 100}%` }}
            />
          )}
        </div>
      </div>
    </div>
  );
}