the download card is a column, so the title stops escaping it
the thumbnail, the title and the Download button shared one row. a long title — which on YouTube is most of them — competed with the button for the width and won, running past the card's own border. `truncate` was already on the title and could not help: it only bites when the box is actually bounded, and a flex sibling that is free to be pushed out means it never is. adding more min-w-0 would have been guessing at that; splitting the row removes the competition. so the card is a column now: thumbnail and text on the top row, the action on its own below. the title has the whole width to truncate against, and the button has a row it cannot be squeezed out of — which also means it stays put as titles change length, rather than the layout shifting per result. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
+46
-37
@@ -252,48 +252,57 @@ export const VideoDownloadDialog = ({ fileBrowserManager }: VideoDownloadDialogP
|
||||
{entries.map((e, i) => (
|
||||
<div
|
||||
key={`${e.url}-${i}`}
|
||||
className="flex items-center gap-3 rounded-md border border-duck-dark/10 bg-background/40 p-2"
|
||||
/*
|
||||
A COLUMN, not a row. The title, the thumbnail and the button used to share one
|
||||
line, so a long title — which is most of them — competed with the button for width
|
||||
and won: `truncate` cannot bite while a sibling can be pushed out of the card.
|
||||
Split, the title has the whole width to truncate against and the button has a row
|
||||
it cannot be squeezed out of.
|
||||
*/
|
||||
className="flex flex-col gap-2 rounded-md border border-duck-dark/10 bg-background/40 p-2"
|
||||
>
|
||||
<div className="flex h-12 w-20 shrink-0 items-center justify-center overflow-hidden rounded bg-duck-dark/10">
|
||||
{e.status === 'loading' ? (
|
||||
<Loader2 size={16} className="animate-spin text-duck-dark/40" />
|
||||
) : e.status === 'error' ? (
|
||||
<AlertCircle size={16} className="text-destructive/70" />
|
||||
) : e.thumbnail && !audioOnly ? (
|
||||
<img src={e.thumbnail} alt="" className="h-full w-full object-cover" />
|
||||
) : (
|
||||
<Music size={16} className="text-duck-dark/40" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<div className="flex h-12 w-20 shrink-0 items-center justify-center overflow-hidden rounded bg-duck-dark/10">
|
||||
{e.status === 'loading' ? (
|
||||
<Loader2 size={16} className="animate-spin text-duck-dark/40" />
|
||||
) : e.status === 'error' ? (
|
||||
<AlertCircle size={16} className="text-destructive/70" />
|
||||
) : e.thumbnail && !audioOnly ? (
|
||||
<img src={e.thumbnail} alt="" className="h-full w-full object-cover" />
|
||||
) : (
|
||||
<Music size={16} className="text-duck-dark/40" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
{e.status === 'loading' ? (
|
||||
<div className="space-y-1.5">
|
||||
<div className="h-3 w-3/4 rounded bg-duck-dark/10" />
|
||||
<div className="h-2.5 w-1/3 rounded bg-duck-dark/10" />
|
||||
</div>
|
||||
) : e.status === 'error' ? (
|
||||
<>
|
||||
<p className="truncate text-sm font-medium text-destructive">
|
||||
{t('videoDownload.couldNotFetch')}
|
||||
</p>
|
||||
<p className="truncate text-xs text-duck-dark/50">{e.error || e.url}</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="truncate text-sm font-medium text-duck-dark" title={e.title}>
|
||||
{e.title || e.url}
|
||||
</p>
|
||||
<p className="truncate text-xs text-duck-dark/50">
|
||||
{[e.uploader, fmtDuration(e.duration)].filter(Boolean).join(' · ')}
|
||||
</p>
|
||||
{e.dl === 'error' && <p className="truncate text-xs text-destructive">{e.dlError}</p>}
|
||||
</>
|
||||
)}
|
||||
<div className="min-w-0 flex-1">
|
||||
{e.status === 'loading' ? (
|
||||
<div className="space-y-1.5">
|
||||
<div className="h-3 w-3/4 rounded bg-duck-dark/10" />
|
||||
<div className="h-2.5 w-1/3 rounded bg-duck-dark/10" />
|
||||
</div>
|
||||
) : e.status === 'error' ? (
|
||||
<>
|
||||
<p className="truncate text-sm font-medium text-destructive">
|
||||
{t('videoDownload.couldNotFetch')}
|
||||
</p>
|
||||
<p className="truncate text-xs text-duck-dark/50">{e.error || e.url}</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="truncate text-sm font-medium text-duck-dark" title={e.title}>
|
||||
{e.title || e.url}
|
||||
</p>
|
||||
<p className="truncate text-xs text-duck-dark/50">
|
||||
{[e.uploader, fmtDuration(e.duration)].filter(Boolean).join(' · ')}
|
||||
</p>
|
||||
{e.dl === 'error' && <p className="truncate text-xs text-destructive">{e.dlError}</p>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{e.status === 'ready' && (
|
||||
<div className="shrink-0">
|
||||
<div className="flex justify-end">
|
||||
{e.dl === 'done' ? (
|
||||
<span className="flex items-center gap-1 text-xs font-medium text-duck-teal">
|
||||
<Check size={14} /> {t('videoDownload.saved')}
|
||||
|
||||
Reference in New Issue
Block a user