Spaces:
Runtime error
Runtime error
Download src/components/queue.tsx from RalphThings/yue2-studio: direct link, hf CLI and curl.
- Browser
- Download file 5.61 kB
-
https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/src/components/queue.tsx
- Command line
-
hf download hf://spaces/RalphThings/yue2-studio/src/components/queue.tsx
-
curl -L -o queue.tsx https://huggingface.co/spaces/RalphThings/yue2-studio/resolve/main/src/components/queue.tsx
5.61 kB
| "use client"; | |
| import { AnimatePresence, motion } from "motion/react"; | |
| import { DownloadSimple, Play, Prohibit, Warning } from "@phosphor-icons/react"; | |
| import { Panel } from "@/components/ui"; | |
| import { downloadName } from "@/lib/download"; | |
| import { explainJobError } from "@/lib/errors"; | |
| import { progressPercent } from "@/lib/progress"; | |
| import { STAGE_LABEL, type Job } from "@/lib/types"; | |
| export function Queue({ | |
| jobs, | |
| selectedId, | |
| onSelect, | |
| onCancel, | |
| }: { | |
| jobs: Job[]; | |
| selectedId: string | null; | |
| onSelect: (job: Job) => void; | |
| onCancel: (job: Job) => void; | |
| }) { | |
| const running = jobs.filter((job) => !TERMINAL.has(job.stage)).length; | |
| return ( | |
| <Panel | |
| title="Takes" | |
| hint={running > 0 ? `${running} on the desk` : undefined} | |
| className="overflow-hidden" | |
| > | |
| {jobs.length === 0 ? ( | |
| <div className="rounded-console border border-dashed border-line-strong px-5 py-8 text-center"> | |
| <p className="text-[13px] text-ink">Nothing rendered yet</p> | |
| <p className="mx-auto mt-1 max-w-[34ch] text-[12px] leading-snug text-ink-faint"> | |
| Write a style and some lyrics, then hit render. Every take stays here with its seed and | |
| its score so you can go back to it. | |
| </p> | |
| </div> | |
| ) : ( | |
| <ul className="flex flex-col gap-1.5"> | |
| <AnimatePresence initial={false}> | |
| {jobs.map((job) => ( | |
| <motion.li | |
| key={job.id} | |
| layout | |
| initial={{ opacity: 0, y: -6 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| exit={{ opacity: 0 }} | |
| transition={{ duration: 0.18 }} | |
| > | |
| <Row | |
| job={job} | |
| selected={job.id === selectedId} | |
| onSelect={() => onSelect(job)} | |
| onCancel={() => onCancel(job)} | |
| /> | |
| </motion.li> | |
| ))} | |
| </AnimatePresence> | |
| </ul> | |
| )} | |
| </Panel> | |
| ); | |
| } | |
| const TERMINAL = new Set(["done", "failed", "cancelled"]); | |
| function Row({ | |
| job, | |
| selected, | |
| onSelect, | |
| onCancel, | |
| }: { | |
| job: Job; | |
| selected: boolean; | |
| onSelect: () => void; | |
| onCancel: () => void; | |
| }) { | |
| const active = !TERMINAL.has(job.stage); | |
| const failed = job.stage === "failed"; | |
| const percent = progressPercent(job); | |
| // Keep the raw text on the title attribute: the plain version is for acting | |
| // on, the original is for diagnosing. | |
| const explained = failed ? explainJobError(job.error) : null; | |
| return ( | |
| <div | |
| className={`group relative overflow-hidden rounded-console border transition-colors duration-150 ${ | |
| selected ? "border-citron/50 bg-citron/5" : "border-line bg-raised hover:border-line-strong" | |
| }`} | |
| > | |
| <button | |
| type="button" | |
| onClick={onSelect} | |
| disabled={job.stage !== "done"} | |
| className="flex w-full items-center gap-3 px-3 py-2.5 text-left disabled:cursor-default" | |
| > | |
| <span | |
| className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-console ${ | |
| failed ? "bg-alarm/15 text-alarm" : selected ? "bg-citron text-void" : "bg-void text-ink-faint" | |
| }`} | |
| > | |
| {failed ? <Warning size={13} weight="fill" /> : <Play size={12} weight="fill" />} | |
| </span> | |
| <span className="min-w-0 flex-1"> | |
| <span className="block truncate text-[13px] text-ink">{job.title}</span> | |
| <span | |
| className={`block truncate text-[11.5px] ${failed ? "text-alarm" : "text-ink-faint"}`} | |
| title={failed ? (job.error ?? undefined) : undefined} | |
| > | |
| {failed ? (explained ?? job.error) : STAGE_LABEL[job.stage]} | |
| {active && percent !== null ? ` · ${percent}%` : ""} | |
| {active && percent === null && job.queuePosition | |
| ? ` · ${job.queuePosition} ahead` | |
| : ""} | |
| </span> | |
| </span> | |
| <span className="shrink-0 font-mono text-[11px] text-ink-faint"> | |
| {job.seedUsed.toString(36).slice(0, 6)} | |
| </span> | |
| </button> | |
| <div className="absolute top-2 right-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100"> | |
| {job.stage === "done" && job.audio ? ( | |
| <a | |
| href={job.audio.url} | |
| download={downloadName(job)} | |
| onClick={(event) => event.stopPropagation()} | |
| className="flex h-6 w-6 items-center justify-center rounded-console bg-void text-ink-dim transition-colors hover:text-citron" | |
| aria-label="Download this take" | |
| > | |
| <DownloadSimple size={12} weight="bold" /> | |
| </a> | |
| ) : null} | |
| {active ? ( | |
| <button | |
| type="button" | |
| onClick={onCancel} | |
| className="flex h-6 w-6 items-center justify-center rounded-console bg-void text-ink-dim transition-colors hover:text-alarm" | |
| aria-label="Stop this take" | |
| > | |
| <Prohibit size={12} weight="bold" /> | |
| </button> | |
| ) : null} | |
| </div> | |
| {active ? ( | |
| percent === null ? ( | |
| // No step reporting, so show motion rather than a number we guessed. | |
| <div className="h-[2px] overflow-hidden bg-line"> | |
| <div className="h-full w-1/3 animate-pulse bg-citron" /> | |
| </div> | |
| ) : ( | |
| <div | |
| className="h-[2px] bg-citron transition-[width] duration-300 ease-out" | |
| style={{ width: `${Math.max(3, percent)}%` }} | |
| /> | |
| ) | |
| ) : null} | |
| </div> | |
| ); | |
| } | |