feat: Takeout walkthrough, design-system restyle, replacing import
Adds a seven-step in-app guide to exporting subscriptions from Google Takeout, with the real URLs opened in the system browser. Restyles the app onto the supplied design system: slate/sky palette, 9-15px type ladder, outline-first controls, tiered radii, borders for separation and shadows only for elevation. Light and dark are both designed, with a System/Light/Dark control and a pre-paint script so the window does not flash light on a dark machine. Importing now replaces the subscription list rather than merging, per request. Because that can delete downloaded files, a confirmation dialog names exactly what will go first.
This commit is contained in:
+35
-27
@@ -21,52 +21,60 @@ export default function VideoRow({
|
||||
const src = thumbSrc(item, online);
|
||||
|
||||
return (
|
||||
<div className="group flex gap-4 rounded-xl p-3 hover:bg-surface transition-colors">
|
||||
<button onClick={onOpen}
|
||||
className="relative shrink-0 w-44 aspect-video rounded-lg overflow-hidden bg-raised cursor-pointer">
|
||||
<li
|
||||
className="flex items-center gap-3 rounded-lg border border-slate-200 bg-slate-50 p-2
|
||||
hover:border-slate-300 dark:border-slate-800 dark:bg-slate-800/50
|
||||
dark:hover:border-slate-700"
|
||||
>
|
||||
<button
|
||||
onClick={onOpen}
|
||||
className="relative aspect-video w-32 shrink-0 cursor-pointer overflow-hidden rounded
|
||||
bg-slate-200 dark:bg-slate-800"
|
||||
>
|
||||
{src ? (
|
||||
<img src={src} alt="" loading="lazy"
|
||||
className="size-full object-cover group-hover:scale-105 transition-transform duration-300" />
|
||||
<img src={src} alt="" loading="lazy" className="size-full object-cover" />
|
||||
) : (
|
||||
<div className="size-full grid place-items-center text-muted text-xs px-2 text-center">
|
||||
No thumbnail cached
|
||||
</div>
|
||||
<span className="grid size-full place-items-center px-1 text-center text-[10px] text-slate-400">
|
||||
No thumbnail
|
||||
</span>
|
||||
)}
|
||||
{item.is_short && (
|
||||
<span className="absolute top-1.5 left-1.5 rounded bg-black/75 px-1.5 py-0.5 text-[10px] font-semibold">
|
||||
SHORT
|
||||
<span
|
||||
className="absolute left-1 top-1 rounded bg-slate-950/75 px-1 py-0.5 text-[9px]
|
||||
font-bold uppercase tracking-widest leading-none text-white"
|
||||
>
|
||||
Short
|
||||
</span>
|
||||
)}
|
||||
{downloaded && (
|
||||
<span className="absolute bottom-1.5 right-1.5 rounded bg-emerald-500/90 px-1.5 py-0.5 text-[10px] font-semibold text-black">
|
||||
OFFLINE
|
||||
<span
|
||||
className="absolute bottom-1 right-1 rounded bg-sky-500 px-1 py-0.5 text-[9px]
|
||||
font-bold uppercase tracking-widest leading-none text-white"
|
||||
>
|
||||
Offline
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<button onClick={onOpen} className="text-left w-full cursor-pointer">
|
||||
<h3 className="font-medium leading-snug line-clamp-2 group-hover:text-white">
|
||||
{item.title}
|
||||
</h3>
|
||||
<button onClick={onOpen} className="w-full cursor-pointer text-left">
|
||||
<h3 className="line-clamp-2 text-[13px] font-medium leading-snug">{item.title}</h3>
|
||||
</button>
|
||||
<div className="mt-1 text-sm text-muted truncate">{item.channel_title}</div>
|
||||
<div className="mt-0.5 text-xs text-muted">
|
||||
{[compactViews(item.views), relativeTime(item.published)]
|
||||
.filter(Boolean)
|
||||
.join(" · ")}
|
||||
<div className="mt-1 truncate text-[12px] text-slate-500 dark:text-slate-400">
|
||||
{item.channel_title}
|
||||
</div>
|
||||
<div className="mt-0.5 text-[11px] text-slate-400 dark:text-slate-500">
|
||||
{[compactViews(item.views), relativeTime(item.published)].filter(Boolean).join(" · ")}
|
||||
</div>
|
||||
{(live?.error ?? item.error) && (live?.state ?? item.state) === "failed" && (
|
||||
<div className="mt-1 text-xs text-red-400 line-clamp-1">
|
||||
<div className="mt-1 line-clamp-1 text-[11px] text-red-600 dark:text-red-400">
|
||||
{live?.error ?? item.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 self-center">
|
||||
<DownloadButton item={item} live={live} online={online}
|
||||
onDownload={onDownload} onCancel={onCancel} onDelete={onDelete} />
|
||||
</div>
|
||||
</div>
|
||||
<DownloadButton item={item} live={live} online={online}
|
||||
onDownload={onDownload} onCancel={onCancel} onDelete={onDelete} />
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user