Add hover popover to nav download indicator
Shows each active download (title + progress bar) and background task (label, phase, done/total + bar) on hover. Pure CSS group-hover, no JS state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,20 +114,57 @@ function DownloadIndicator() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
to="/downloads"
|
||||
className="flex items-center gap-1.5 px-2 py-1 rounded-lg bg-zinc-800 hover:bg-zinc-700 transition-colors text-xs text-zinc-300 shrink-0"
|
||||
title={`${totalActive} task${totalActive > 1 ? "s" : ""} in progress`}
|
||||
>
|
||||
<svg className="w-3 h-3 animate-spin text-zinc-400 shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-20" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" />
|
||||
<path className="opacity-80" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
|
||||
</svg>
|
||||
{label}
|
||||
{totalActive > 1 && (
|
||||
<span className="hidden sm:inline text-zinc-500">+{totalActive - 1}</span>
|
||||
)}
|
||||
</Link>
|
||||
<div className="relative group shrink-0">
|
||||
<Link
|
||||
to="/downloads"
|
||||
className="flex items-center gap-1.5 px-2 py-1 rounded-lg bg-zinc-800 hover:bg-zinc-700 transition-colors text-xs text-zinc-300"
|
||||
>
|
||||
<svg className="w-3 h-3 animate-spin text-zinc-400 shrink-0" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-20" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" />
|
||||
<path className="opacity-80" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
|
||||
</svg>
|
||||
{label}
|
||||
{totalActive > 1 && (
|
||||
<span className="hidden sm:inline text-zinc-500">+{totalActive - 1}</span>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{/* Hover popover */}
|
||||
<div className="absolute top-[calc(100%+6px)] right-0 z-50
|
||||
invisible opacity-0 group-hover:visible group-hover:opacity-100
|
||||
transition-all duration-100 pointer-events-none">
|
||||
<div className="bg-zinc-900 border border-zinc-800 rounded-xl shadow-2xl p-3 min-w-[220px] max-w-[280px] flex flex-col gap-2">
|
||||
{activeDownloads.map((d) => (
|
||||
<div key={d.id}>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<p className="text-xs text-zinc-200 truncate">{d.video_title || "Downloading…"}</p>
|
||||
<span className="text-[10px] text-zinc-400 tabular-nums shrink-0">{(d.progress_percent ?? 0).toFixed(0)}%</span>
|
||||
</div>
|
||||
<div className="h-0.5 bg-zinc-800 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent rounded-full transition-all duration-300" style={{ width: `${d.progress_percent ?? 0}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{tasks.map((task) => {
|
||||
const pct = task.total > 0 ? (task.done / task.total) * 100 : 0;
|
||||
return (
|
||||
<div key={task.id}>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<p className="text-xs text-zinc-200 truncate">{task.label}</p>
|
||||
{task.total > 0 && (
|
||||
<span className="text-[10px] text-zinc-400 tabular-nums shrink-0">{task.done}/{task.total}</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[10px] text-zinc-500 mb-1">{task.phase || "Running…"}</p>
|
||||
<div className="h-0.5 bg-zinc-800 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent rounded-full transition-all duration-300" style={{ width: `${pct}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user