Spaces:
Running
Running
Commit
·
9b37b82
1
Parent(s):
d4e8cf1
add a delay to not load all videos at once
Browse files
src/app/interface/video-card/index.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use client"
|
2 |
|
3 |
-
import { useRef, useState } from "react"
|
4 |
import dynamic from "next/dynamic"
|
5 |
import Link from "next/link"
|
6 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
@@ -22,11 +22,13 @@ export function VideoCard({
|
|
22 |
className = "",
|
23 |
layout = "normal",
|
24 |
onSelect,
|
|
|
25 |
}: {
|
26 |
video: VideoInfo
|
27 |
className?: string
|
28 |
layout?: "normal" | "compact"
|
29 |
onSelect?: (video: VideoInfo) => void
|
|
|
30 |
}) {
|
31 |
const ref = useRef<HTMLVideoElement>(null)
|
32 |
const [duration, setDuration] = useState(0)
|
@@ -36,6 +38,7 @@ export function VideoCard({
|
|
36 |
`https://huggingface.co/datasets/jbilcke-hf/ai-tube-index/resolve/main/videos/${video.id}.webp`
|
37 |
)
|
38 |
const [videoThumbnailReady, setVideoThumbnailReady] = useState(false)
|
|
|
39 |
|
40 |
const isCompact = layout === "compact"
|
41 |
|
@@ -67,6 +70,12 @@ export function VideoCard({
|
|
67 |
}
|
68 |
}
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
return (
|
71 |
<Link href={`/watch?v=${video.id}`}>
|
72 |
<div
|
@@ -89,28 +98,37 @@ export function VideoCard({
|
|
89 |
isCompact ? `w-42 h-[94px]` : `aspect-video`
|
90 |
)}
|
91 |
>
|
92 |
-
<div className=
|
93 |
-
|
|
|
|
|
|
|
94 |
ref={ref}
|
95 |
src={video.assetUrl}
|
96 |
className={cn(
|
97 |
`w-full h-full`,
|
|
|
98 |
duration > 0 ? `opacity-100`: 'opacity-0',
|
99 |
`transition-all duration-500`,
|
100 |
)}
|
101 |
onLoadedMetadata={handleLoad}
|
102 |
muted
|
103 |
-
/>
|
104 |
<img
|
105 |
src={videoThumbnail}
|
106 |
className={cn(
|
107 |
`absolute`,
|
108 |
-
`
|
|
|
|
|
109 |
videoThumbnailReady ? `opacity-100`: 'opacity-0',
|
110 |
`hover:opacity-0 w-full h-full top-0 z-30`,
|
111 |
//`pointer-events-none`,
|
112 |
-
`transition-all duration-500 hover:delay-
|
113 |
)}
|
|
|
|
|
|
|
114 |
onLoad={() => {
|
115 |
setVideoThumbnailReady(true)
|
116 |
}}
|
@@ -122,7 +140,8 @@ export function VideoCard({
|
|
122 |
</div>
|
123 |
|
124 |
<div className={cn(
|
125 |
-
|
|
|
126 |
`w-full flex flex-row items-end justify-end`
|
127 |
)}>
|
128 |
<div className={cn(
|
|
|
1 |
"use client"
|
2 |
|
3 |
+
import { useEffect, useRef, useState } from "react"
|
4 |
import dynamic from "next/dynamic"
|
5 |
import Link from "next/link"
|
6 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
|
|
22 |
className = "",
|
23 |
layout = "normal",
|
24 |
onSelect,
|
25 |
+
index
|
26 |
}: {
|
27 |
video: VideoInfo
|
28 |
className?: string
|
29 |
layout?: "normal" | "compact"
|
30 |
onSelect?: (video: VideoInfo) => void
|
31 |
+
index: number
|
32 |
}) {
|
33 |
const ref = useRef<HTMLVideoElement>(null)
|
34 |
const [duration, setDuration] = useState(0)
|
|
|
38 |
`https://huggingface.co/datasets/jbilcke-hf/ai-tube-index/resolve/main/videos/${video.id}.webp`
|
39 |
)
|
40 |
const [videoThumbnailReady, setVideoThumbnailReady] = useState(false)
|
41 |
+
const [shouldLoadVideo, setShouldLoadVideo] = useState(false)
|
42 |
|
43 |
const isCompact = layout === "compact"
|
44 |
|
|
|
70 |
}
|
71 |
}
|
72 |
|
73 |
+
useEffect(() => {
|
74 |
+
setTimeout(() => {
|
75 |
+
setShouldLoadVideo(true)
|
76 |
+
}, index * 500)
|
77 |
+
}, [index])
|
78 |
+
|
79 |
return (
|
80 |
<Link href={`/watch?v=${video.id}`}>
|
81 |
<div
|
|
|
98 |
isCompact ? `w-42 h-[94px]` : `aspect-video`
|
99 |
)}
|
100 |
>
|
101 |
+
<div className={cn(
|
102 |
+
`relative w-full`,
|
103 |
+
isCompact ? `w-42 h-[94px]` : `aspect-video`
|
104 |
+
)}>
|
105 |
+
{videoThumbnailReady && shouldLoadVideo ? <video
|
106 |
ref={ref}
|
107 |
src={video.assetUrl}
|
108 |
className={cn(
|
109 |
`w-full h-full`,
|
110 |
+
`aspect-video`,
|
111 |
duration > 0 ? `opacity-100`: 'opacity-0',
|
112 |
`transition-all duration-500`,
|
113 |
)}
|
114 |
onLoadedMetadata={handleLoad}
|
115 |
muted
|
116 |
+
/> : null}
|
117 |
<img
|
118 |
src={videoThumbnail}
|
119 |
className={cn(
|
120 |
`absolute`,
|
121 |
+
`aspect-video`,
|
122 |
+
// `aspect-video object-cover`,
|
123 |
+
`rounded-lg overflow-hidden`,
|
124 |
videoThumbnailReady ? `opacity-100`: 'opacity-0',
|
125 |
`hover:opacity-0 w-full h-full top-0 z-30`,
|
126 |
//`pointer-events-none`,
|
127 |
+
`transition-all duration-500 hover:delay-300 ease-in-out`,
|
128 |
)}
|
129 |
+
onMouseEnter={() => {
|
130 |
+
setShouldLoadVideo(true)
|
131 |
+
}}
|
132 |
onLoad={() => {
|
133 |
setVideoThumbnailReady(true)
|
134 |
}}
|
|
|
140 |
</div>
|
141 |
|
142 |
<div className={cn(
|
143 |
+
// `aspect-video`,
|
144 |
+
`z-40`,
|
145 |
`w-full flex flex-row items-end justify-end`
|
146 |
)}>
|
147 |
<div className={cn(
|
src/app/interface/video-list/index.tsx
CHANGED
@@ -36,13 +36,14 @@ export function VideoList({
|
|
36 |
className,
|
37 |
)}
|
38 |
>
|
39 |
-
{videos.map((video) => (
|
40 |
<VideoCard
|
41 |
key={video.id}
|
42 |
video={video}
|
43 |
className="w-full"
|
44 |
layout={layout === "vertical" ? "compact" : "normal"}
|
45 |
onSelect={onSelect}
|
|
|
46 |
/>
|
47 |
))}
|
48 |
</div>
|
|
|
36 |
className,
|
37 |
)}
|
38 |
>
|
39 |
+
{videos.map((video, i) => (
|
40 |
<VideoCard
|
41 |
key={video.id}
|
42 |
video={video}
|
43 |
className="w-full"
|
44 |
layout={layout === "vertical" ? "compact" : "normal"}
|
45 |
onSelect={onSelect}
|
46 |
+
index={i}
|
47 |
/>
|
48 |
))}
|
49 |
</div>
|