diff --git a/frontend/src/components/VideoCard.jsx b/frontend/src/components/VideoCard.jsx index 0424960..d01a0a1 100644 --- a/frontend/src/components/VideoCard.jsx +++ b/frontend/src/components/VideoCard.jsx @@ -33,10 +33,8 @@ function IconBtn({ onClick, title, active, pending, children }) { onClick={(e) => { e.stopPropagation(); onClick(e); }} title={title} className={clsx( - "flex items-center justify-center w-6 h-6 rounded-full transition-all duration-150", - active - ? "text-accent" - : "text-zinc-600 hover:text-zinc-200", + "flex items-center justify-center w-7 h-7 rounded-full transition-all duration-150", + active ? "text-accent" : "text-zinc-600 hover:text-zinc-200", pending && "opacity-60 cursor-default", )} > @@ -104,7 +102,6 @@ function ThumbnailBlock({ video, isWatched, duration, calmMode, onDismiss, class )} - {/* Dismiss */} {video.is_recommended && !calmMode && ( )} - {/* Duration */} {duration && ( - + {duration} )} - {/* Resolution */} {video.download_resolution && ( - + {video.download_resolution} )} - {/* Watched dot */} {isWatched && ( )} - {/* Play hover overlay */} -
-
+
+
- {/* Progress bar */} {video.watch_progress_seconds > 0 && video.duration_seconds > 0 && (
e.stopPropagation()}> +
e.stopPropagation()}> navigate(`/watch/${video.youtube_video_id}`)} title="Watch"> @@ -251,40 +245,53 @@ export default function VideoCard({ video, size = "md", onDismiss, variant = "gr
); - // ── List variant ───────────────────────────────────────────────────────── + // ── List variant ──────────────────────────────────────────────────────────── if (variant === "list") { return (
navigate(`/watch/${video.youtube_video_id}`)} - className="group flex gap-5 px-3 py-3.5 rounded-2xl cursor-pointer hover:bg-zinc-800/50 transition-colors duration-150" + className="group flex gap-3 sm:gap-4 px-2 sm:px-3 py-2 sm:py-3 rounded-xl cursor-pointer hover:bg-zinc-800/50 transition-colors duration-150" > + {/* Thumbnail — compact on mobile, wide on desktop */} dismissMut.mutate()} - className="w-56 sm:w-72 aspect-video rounded-xl shrink-0" + className="w-32 sm:w-60 md:w-72 aspect-video rounded-lg shrink-0" /> -
+
{/* Title */} -

+

{video.title}

- {/* Channel · date · badges */} -
- {video.channel_name} - {date && ·} - {date && {date}} + {/* Channel row */} +
+ {avatarUrl && ( + + )} + {video.channel_name} + {date && ( + <> + · + {date} + + )} +
+ + {/* Views + badges */} +
+ {video.view_count > 0 && {formatViews(video.view_count)}} {video.is_recommended && !calmMode && ( - + Discover )} {isDormant && !calmMode && ( - zzz + zzz )} {channelNote && ( @@ -295,17 +302,15 @@ export default function VideoCard({ video, size = "md", onDismiss, variant = "gr )}
- {/* Description */} - {video.description ? ( -

+ {/* Description — desktop only, 2 lines max */} + {video.description && ( +

{video.description.replace(/\n+/g, " ")}

- ) : ( -
)} - {/* Actions — fade in on hover */} -
+ {/* Actions — always visible on mobile, fade on desktop */} +
{actions}
@@ -313,10 +318,7 @@ export default function VideoCard({ video, size = "md", onDismiss, variant = "gr ); } - // ── Grid variant ───────────────────────────────────────────────────────── - const avatarUrl = video.channel_thumbnail_url ?? channelMeta?.thumbnail_url ?? null; - const avatarLetter = video.channel_name?.[0]?.toUpperCase() ?? "?"; - + // ── Grid variant ──────────────────────────────────────────────────────────── return (
navigate(`/watch/${video.youtube_video_id}`)} @@ -335,56 +337,62 @@ export default function VideoCard({ video, size = "md", onDismiss, variant = "gr className="aspect-video rounded-t-2xl overflow-hidden" /> -
+
{/* Channel avatar */} -
{ e.stopPropagation(); navigate(`/channels/${video.channel_id}`); }}> +
{ e.stopPropagation(); navigate(`/channels/${video.channel_id}`); }} + > {avatarUrl ? ( - + ) : ( -
+
{avatarLetter}
)}
{/* Text + actions */} -
-

+

+

{video.title}

-
- {video.channel_name} +
+ {video.channel_name} {channelNote && ( - + )} {isDormant && !calmMode && ( - zzz + zzz )} {video.is_recommended && !calmMode && ( - + Discover )}
-
+
{date && {date}} - {video.view_count > 0 && <>·{formatViews(video.view_count)}} + {video.view_count > 0 && ( + <> + · + {formatViews(video.view_count)} + + )}
- {video.description && ( -

- {video.description.replace(/\n+/g, " ")} -

- )} - - {/* Actions — fade in on hover */} -
+ {/* Actions — desktop hover only (touch users tap to watch) */} +
{actions}