hybrid-timeline.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { cn } from "@/lib/utils";
  2. import type { TxStatus } from "@/lib/explorer-types";
  3. const STEPS = [
  4. {
  5. key: "submit" as const,
  6. title: "Submit",
  7. body: "Transaction enters the private permissioned layer.",
  8. },
  9. {
  10. key: "confirm" as const,
  11. title: "Confirm",
  12. body: "Validators finalize it on the private layer.",
  13. },
  14. {
  15. key: "anchor" as const,
  16. title: "Anchor",
  17. body: "A public-chain commitment proves the private state.",
  18. },
  19. ];
  20. function stepState(
  21. status: TxStatus,
  22. key: "submit" | "confirm" | "anchor",
  23. ): "done" | "active" | "todo" {
  24. if (status === "pending") {
  25. if (key === "submit") return "active";
  26. return "todo";
  27. }
  28. if (status === "confirmed") {
  29. if (key === "submit") return "done";
  30. if (key === "confirm") return "active";
  31. return "todo";
  32. }
  33. // anchored
  34. return "done";
  35. }
  36. export function HybridTimeline({ status }: { status: TxStatus }) {
  37. return (
  38. <ol className="grid gap-4 md:grid-cols-3">
  39. {STEPS.map((step, i) => {
  40. const state = stepState(status, step.key);
  41. return (
  42. <li
  43. key={step.key}
  44. className={cn(
  45. "relative rounded-xl border p-5",
  46. state === "done" && "border-proof/40 bg-proof-muted/40",
  47. state === "active" && "border-pending/50 bg-pending-muted/40",
  48. state === "todo" && "border-border bg-card",
  49. )}
  50. >
  51. <div className="flex items-center gap-2">
  52. <span
  53. className={cn(
  54. "flex h-7 w-7 items-center justify-center rounded-full font-mono text-xs font-medium",
  55. state === "done" && "bg-proof text-background",
  56. state === "active" && "bg-pending text-background",
  57. state === "todo" && "bg-muted text-muted-foreground",
  58. )}
  59. >
  60. {i + 1}
  61. </span>
  62. <span className="font-display text-base font-semibold">
  63. {step.title}
  64. </span>
  65. </div>
  66. <p className="mt-2 text-sm leading-relaxed text-muted-foreground">
  67. {step.body}
  68. </p>
  69. <p className="mt-3 text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
  70. {state === "done" && "complete"}
  71. {state === "active" && "current"}
  72. {state === "todo" && "waiting"}
  73. </p>
  74. </li>
  75. );
  76. })}
  77. </ol>
  78. );
  79. }