jbilcke-hf's picture
jbilcke-hf HF Staff
playing with stable video diffusion
4c34e70
raw
history blame
4.33 kB
import { useRef, useState } from "react"
import { RiCheckboxCircleFill } from "react-icons/ri"
import { cn } from "@/lib/utils"
import { VideoInfo } from "@/types"
import { formatDuration } from "@/lib/formatDuration"
import { formatTimeAgo } from "@/lib/formatTimeAgo"
import Link from "next/link"
const defaultChannelThumbnail = "/huggingface-avatar.jpeg"
export function VideoCard({
video,
className = "",
layout = "normal",
onSelect,
}: {
video: VideoInfo
className?: string
layout?: "normal" | "compact"
onSelect?: (video: VideoInfo) => void
}) {
const ref = useRef<HTMLVideoElement>(null)
const [duration, setDuration] = useState(0)
const [channelThumbnail, setChannelThumbnail] = useState(video.channel.thumbnail)
const isCompact = layout === "compact"
const handlePointerEnter = () => {
// ref.current?.load()
ref.current?.play()
}
const handlePointerLeave = () => {
ref.current?.pause()
// ref.current?.load()
}
const handleLoad = () => {
if (ref.current?.readyState) {
setDuration(ref.current.duration)
}
}
const handleClick = () => {
onSelect?.(video)
}
const handleBadChannelThumbnail = () => {
try {
if (channelThumbnail !== defaultChannelThumbnail) {
setChannelThumbnail(defaultChannelThumbnail)
}
} catch (err) {
}
}
return (
<Link href={`/watch?v=${video.id}`}>
<div
className={cn(
`w-full flex`,
isCompact ? `flex-row h-24 py-1 space-x-2` : `flex-col space-y-3`,
`bg-line-900`,
`cursor-pointer`,
className,
)}
onPointerEnter={handlePointerEnter}
onPointerLeave={handlePointerLeave}
// onClick={handleClick}
>
{/* VIDEO BLOCK */}
<div
className={cn(
`flex flex-col items-center justify-center`,
`rounded-xl overflow-hidden`,
isCompact ? `w-42 h-[94px]` : `aspect-video`
)}
>
<video
ref={ref}
src={video.assetUrl}
className={cn(
`w-full`
)}
onLoadedMetadata={handleLoad}
muted
/>
<div className={cn(
``,
`w-full flex flex-row items-end justify-end`
)}>
<div className={cn(
`-mt-8`,
`mr-0`,
)}
>
<div className={cn(
`mb-[5px]`,
`mr-[5px]`,
`flex flex-col items-center justify-center text-center`,
`bg-neutral-900 rounded`,
`text-2xs font-semibold px-[3px] py-[1px]`,
)}
>{formatDuration(duration)}</div>
</div>
</div>
</div>
{/* TEXT BLOCK */}
<div className={cn(
`flex flex-row`,
isCompact ? `w-51` : `space-x-4`,
)}>
{isCompact ? null : <div className="flex flex-col">
<div className="flex w-9 rounded-full overflow-hidden">
<img
src={channelThumbnail}
onError={handleBadChannelThumbnail}
/>
</div>
</div>}
<div className={cn(
`flex flex-col`,
isCompact ? `` : `flex-grow`
)}>
<h3 className={cn(
`text-zinc-100 font-medium mb-0 line-clamp-2`,
isCompact ? `text-sm mb-1.5` : `text-base`
)}>{video.label}</h3>
<div className={cn(
`flex flex-row items-center`,
`text-neutral-400 font-normal space-x-1`,
isCompact ? `text-xs` : `text-sm`
)}>
<div>{video.channel.label}</div>
<div><RiCheckboxCircleFill className="" /></div>
</div>
<div className={cn(
`flex flex-row`,
`text-neutral-400 font-normal`,
isCompact ? `text-xs` : `text-sm`,
`space-x-1`
)}>
<div>0 views</div>
<div className="font-semibold scale-125">·</div>
<div>{formatTimeAgo(video.updatedAt)}</div>
</div>
</div>
</div>
</div>
</Link>
)
}