Spaces:
Running
Running
Commit
•
a2c7711
1
Parent(s):
22d3c77
make sure user-generated content is not confused with HF content
Browse files- declarations.d.ts +2 -1
- package-lock.json +10 -0
- package.json +1 -0
- src/app/interface/default-avatar/index.tsx +48 -0
- src/app/interface/video-card/index.tsx +21 -6
declarations.d.ts
CHANGED
@@ -1 +1,2 @@
|
|
1 |
-
declare module 'markdown-yaml-metadata-parser';
|
|
|
|
1 |
+
declare module 'markdown-yaml-metadata-parser';
|
2 |
+
declare module 'react-string-avatar';
|
package-lock.json
CHANGED
@@ -52,6 +52,7 @@
|
|
52 |
"react-dom": "18.2.0",
|
53 |
"react-icons": "^4.12.0",
|
54 |
"react-smooth-scroll-hook": "^1.3.4",
|
|
|
55 |
"react-tuby": "^0.1.24",
|
56 |
"react-virtualized-auto-sizer": "^1.0.20",
|
57 |
"replicate": "^0.17.0",
|
@@ -5665,6 +5666,15 @@
|
|
5665 |
"react-dom": ">=16.8.0"
|
5666 |
}
|
5667 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5668 |
"node_modules/react-style-singleton": {
|
5669 |
"version": "2.2.1",
|
5670 |
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
|
|
52 |
"react-dom": "18.2.0",
|
53 |
"react-icons": "^4.12.0",
|
54 |
"react-smooth-scroll-hook": "^1.3.4",
|
55 |
+
"react-string-avatar": "^1.2.2",
|
56 |
"react-tuby": "^0.1.24",
|
57 |
"react-virtualized-auto-sizer": "^1.0.20",
|
58 |
"replicate": "^0.17.0",
|
|
|
5666 |
"react-dom": ">=16.8.0"
|
5667 |
}
|
5668 |
},
|
5669 |
+
"node_modules/react-string-avatar": {
|
5670 |
+
"version": "1.2.2",
|
5671 |
+
"resolved": "https://registry.npmjs.org/react-string-avatar/-/react-string-avatar-1.2.2.tgz",
|
5672 |
+
"integrity": "sha512-M2cBIVxZvyGiK0J+YAVqSLgTbhD/EEhAyAzw8AH2OzxO06CjLjuj8GNwf9yRWaY73aQj2RU90eXrhYYSu540Eg==",
|
5673 |
+
"peerDependencies": {
|
5674 |
+
"react": "^16.4.2",
|
5675 |
+
"react-dom": "^16.4.2"
|
5676 |
+
}
|
5677 |
+
},
|
5678 |
"node_modules/react-style-singleton": {
|
5679 |
"version": "2.2.1",
|
5680 |
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
|
package.json
CHANGED
@@ -53,6 +53,7 @@
|
|
53 |
"react-dom": "18.2.0",
|
54 |
"react-icons": "^4.12.0",
|
55 |
"react-smooth-scroll-hook": "^1.3.4",
|
|
|
56 |
"react-tuby": "^0.1.24",
|
57 |
"react-virtualized-auto-sizer": "^1.0.20",
|
58 |
"replicate": "^0.17.0",
|
|
|
53 |
"react-dom": "18.2.0",
|
54 |
"react-icons": "^4.12.0",
|
55 |
"react-smooth-scroll-hook": "^1.3.4",
|
56 |
+
"react-string-avatar": "^1.2.2",
|
57 |
"react-tuby": "^0.1.24",
|
58 |
"react-virtualized-auto-sizer": "^1.0.20",
|
59 |
"replicate": "^0.17.0",
|
src/app/interface/default-avatar/index.tsx
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import RSA from "react-string-avatar"
|
4 |
+
|
5 |
+
export type DefaultAvatarProps = {
|
6 |
+
username?: string
|
7 |
+
initials?: string
|
8 |
+
bgColor?: string
|
9 |
+
textColor?: string
|
10 |
+
roundShape?: boolean
|
11 |
+
cornerRadius?: number
|
12 |
+
pictureFormat?: string
|
13 |
+
pictureResolution?: number
|
14 |
+
width?: number
|
15 |
+
pixelated?: boolean
|
16 |
+
wrapper?: boolean
|
17 |
+
wrapperStyle?: Record<string, any>
|
18 |
+
}
|
19 |
+
|
20 |
+
export type DefaultAvatarComponent = (props: DefaultAvatarProps) => JSX.Element
|
21 |
+
|
22 |
+
const ReactStringAvatar = RSA as DefaultAvatarComponent
|
23 |
+
|
24 |
+
|
25 |
+
export default function DefaultAvatar({
|
26 |
+
username,
|
27 |
+
initials: customInitials,
|
28 |
+
...props
|
29 |
+
}: DefaultAvatarProps): JSX.Element {
|
30 |
+
|
31 |
+
const usernameInitials = `${username || ""}`
|
32 |
+
.trim()
|
33 |
+
.replaceAll("_", " ")
|
34 |
+
.replaceAll("-", " ")
|
35 |
+
.replace(/([a-z])([A-Z])/g, '$1 $2') // split the camel case
|
36 |
+
.split(" ") // split words
|
37 |
+
.map(u => u.trim()[0]) // take first char
|
38 |
+
.slice(0, 2) // keep first 2 chars
|
39 |
+
.join("")
|
40 |
+
.toUpperCase()
|
41 |
+
|
42 |
+
return (
|
43 |
+
<ReactStringAvatar
|
44 |
+
initials={customInitials || usernameInitials}
|
45 |
+
{...props}
|
46 |
+
/>
|
47 |
+
)
|
48 |
+
}
|
src/app/interface/video-card/index.tsx
CHANGED
@@ -1,13 +1,19 @@
|
|
|
|
|
|
1 |
import { useRef, useState } from "react"
|
|
|
|
|
2 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
3 |
|
4 |
import { cn } from "@/lib/utils"
|
5 |
import { VideoInfo } from "@/types"
|
6 |
import { formatDuration } from "@/lib/formatDuration"
|
7 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
8 |
-
import Link from "next/link"
|
9 |
|
10 |
-
const
|
|
|
|
|
|
|
11 |
|
12 |
export function VideoCard({
|
13 |
video,
|
@@ -47,8 +53,8 @@ export function VideoCard({
|
|
47 |
|
48 |
const handleBadChannelThumbnail = () => {
|
49 |
try {
|
50 |
-
if (channelThumbnail
|
51 |
-
setChannelThumbnail(
|
52 |
}
|
53 |
} catch (err) {
|
54 |
|
@@ -113,14 +119,23 @@ export function VideoCard({
|
|
113 |
`flex flex-row`,
|
114 |
isCompact ? `w-51` : `space-x-4`,
|
115 |
)}>
|
116 |
-
{
|
|
|
|
|
117 |
<div className="flex w-9 rounded-full overflow-hidden">
|
118 |
<img
|
119 |
src={channelThumbnail}
|
120 |
onError={handleBadChannelThumbnail}
|
121 |
/>
|
122 |
</div>
|
123 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
<div className={cn(
|
125 |
`flex flex-col`,
|
126 |
isCompact ? `` : `flex-grow`
|
|
|
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"
|
7 |
|
8 |
import { cn } from "@/lib/utils"
|
9 |
import { VideoInfo } from "@/types"
|
10 |
import { formatDuration } from "@/lib/formatDuration"
|
11 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
|
|
12 |
|
13 |
+
const DefaultAvatar = dynamic(() => import("../default-avatar"), {
|
14 |
+
loading: () => null,
|
15 |
+
})
|
16 |
+
|
17 |
|
18 |
export function VideoCard({
|
19 |
video,
|
|
|
53 |
|
54 |
const handleBadChannelThumbnail = () => {
|
55 |
try {
|
56 |
+
if (channelThumbnail) {
|
57 |
+
setChannelThumbnail("")
|
58 |
}
|
59 |
} catch (err) {
|
60 |
|
|
|
119 |
`flex flex-row`,
|
120 |
isCompact ? `w-51` : `space-x-4`,
|
121 |
)}>
|
122 |
+
{
|
123 |
+
isCompact ? null
|
124 |
+
: channelThumbnail ? <div className="flex flex-col">
|
125 |
<div className="flex w-9 rounded-full overflow-hidden">
|
126 |
<img
|
127 |
src={channelThumbnail}
|
128 |
onError={handleBadChannelThumbnail}
|
129 |
/>
|
130 |
</div>
|
131 |
+
</div>
|
132 |
+
: <DefaultAvatar
|
133 |
+
username={video.channel.datasetUser}
|
134 |
+
bgColor="#fde047"
|
135 |
+
textColor="#1c1917"
|
136 |
+
width={36}
|
137 |
+
roundShape
|
138 |
+
/>}
|
139 |
<div className={cn(
|
140 |
`flex flex-col`,
|
141 |
isCompact ? `` : `flex-grow`
|