| |
| |
| |
| import { useEffect, useState } from "react"; |
|
|
| |
| |
| |
| export const MIN_PROGRESS_MS = 1600; |
|
|
| export default function SearchProgress({ |
| mode = "match", |
| count, |
| }: { |
| mode?: "match" | "breed"; |
| count?: number; |
| }) { |
| const dogs = count && count > 0 ? count.toLocaleString() : null; |
| const steps = |
| mode === "breed" |
| ? ["Reading the image", "Classifying across 120 breeds", "Ranking the closest look-alikes"] |
| : [ |
| "Extracting features", |
| dogs ? `Searching ${dogs} dogs` : "Searching the database", |
| "Ranking the closest matches", |
| ]; |
| const subtitle = |
| mode === "breed" |
| ? "Classifying against 120 known breeds" |
| : dogs |
| ? `Comparing against ${dogs} found & unclaimed dogs` |
| : null; |
| const [step, setStep] = useState(0); |
| useEffect(() => { |
| const id = setInterval(() => setStep((s) => Math.min(s + 1, steps.length - 1)), 600); |
| return () => clearInterval(id); |
| }, [steps.length]); |
|
|
| const pct = [34, 68, 95][step]; |
|
|
| return ( |
| <div className="card" role="status" aria-live="polite"> |
| <div className="flex items-center gap-3"> |
| <span |
| className="h-5 w-5 shrink-0 rounded-full border-2 border-leaf-200 border-t-leaf-600 animate-spin motion-reduce:animate-none" |
| aria-hidden |
| /> |
| <div className="min-w-0 flex-1"> |
| <p className="font-semibold text-sm">{steps[step]}…</p> |
| {subtitle && <p className="text-xs text-gray-500">{subtitle}</p>} |
| </div> |
| </div> |
| |
| <div className="mt-3 h-2 rounded-full bg-gray-100 overflow-hidden"> |
| <div |
| className="h-full rounded-full bg-leaf-500 transition-all duration-500 ease-out" |
| style={{ width: `${pct}%` }} |
| /> |
| </div> |
| |
| <ol className="mt-3 grid gap-1"> |
| {steps.map((s, i) => ( |
| <li |
| key={s} |
| className={`flex items-center gap-2 text-xs ${ |
| i < step ? "text-leaf-700" : i === step ? "text-leaf-700 font-medium" : "text-gray-400" |
| }`} |
| > |
| <span |
| aria-hidden |
| className={`h-2 w-2 shrink-0 rounded-full border ${ |
| i <= step ? "bg-leaf-500 border-leaf-500" : "bg-transparent border-gray-300" |
| }`} |
| /> |
| {s} |
| </li> |
| ))} |
| </ol> |
| </div> |
| ); |
| } |
|
|