jbilcke-hf HF staff commited on
Commit
a40111f
1 Parent(s): a3f1817

add link sharing capabilities

Browse files
package-lock.json CHANGED
@@ -48,6 +48,7 @@
48
  "qs": "^6.11.2",
49
  "react": "18.2.0",
50
  "react-circular-progressbar": "^2.1.0",
 
51
  "react-dom": "18.2.0",
52
  "react-icons": "^4.12.0",
53
  "react-smooth-scroll-hook": "^1.3.4",
@@ -72,6 +73,7 @@
72
  "devDependencies": {
73
  "@types/proper-lockfile": "^4.1.2",
74
  "@types/qs": "^6.9.7",
 
75
  "@types/react-virtualized": "^9.21.22",
76
  "@types/sbd": "^1.0.3",
77
  "daisyui": "^3.7.4"
@@ -1768,6 +1770,15 @@
1768
  "csstype": "^3.0.2"
1769
  }
1770
  },
 
 
 
 
 
 
 
 
 
1771
  "node_modules/@types/react-dom": {
1772
  "version": "18.2.7",
1773
  "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
@@ -2825,6 +2836,14 @@
2825
  "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.65.tgz",
2826
  "integrity": "sha512-5E9WgTy95B7i90oISjui9U5Zu7iExUPfU4ygtv4yXEy6zJFE3oQYHCnh5H1jZRPkjphJt2Ml3oQW6M0qtK534A=="
2827
  },
 
 
 
 
 
 
 
 
2828
  "node_modules/create-require": {
2829
  "version": "1.1.1",
2830
  "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@@ -5552,6 +5571,18 @@
5552
  "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
5553
  }
5554
  },
 
 
 
 
 
 
 
 
 
 
 
 
5555
  "node_modules/react-dom": {
5556
  "version": "18.2.0",
5557
  "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -6486,6 +6517,11 @@
6486
  "node": ">=8.0"
6487
  }
6488
  },
 
 
 
 
 
6489
  "node_modules/ts-interface-checker": {
6490
  "version": "0.1.13",
6491
  "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
 
48
  "qs": "^6.11.2",
49
  "react": "18.2.0",
50
  "react-circular-progressbar": "^2.1.0",
51
+ "react-copy-to-clipboard": "^5.1.0",
52
  "react-dom": "18.2.0",
53
  "react-icons": "^4.12.0",
54
  "react-smooth-scroll-hook": "^1.3.4",
 
73
  "devDependencies": {
74
  "@types/proper-lockfile": "^4.1.2",
75
  "@types/qs": "^6.9.7",
76
+ "@types/react-copy-to-clipboard": "^5.0.7",
77
  "@types/react-virtualized": "^9.21.22",
78
  "@types/sbd": "^1.0.3",
79
  "daisyui": "^3.7.4"
 
1770
  "csstype": "^3.0.2"
1771
  }
1772
  },
1773
+ "node_modules/@types/react-copy-to-clipboard": {
1774
+ "version": "5.0.7",
1775
+ "resolved": "https://registry.npmjs.org/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.7.tgz",
1776
+ "integrity": "sha512-Gft19D+as4M+9Whq1oglhmK49vqPhcLzk8WfvfLvaYMIPYanyfLy0+CwFucMJfdKoSFyySPmkkWn8/E6voQXjQ==",
1777
+ "dev": true,
1778
+ "dependencies": {
1779
+ "@types/react": "*"
1780
+ }
1781
+ },
1782
  "node_modules/@types/react-dom": {
1783
  "version": "18.2.7",
1784
  "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
 
2836
  "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.65.tgz",
2837
  "integrity": "sha512-5E9WgTy95B7i90oISjui9U5Zu7iExUPfU4ygtv4yXEy6zJFE3oQYHCnh5H1jZRPkjphJt2Ml3oQW6M0qtK534A=="
2838
  },
2839
+ "node_modules/copy-to-clipboard": {
2840
+ "version": "3.3.3",
2841
+ "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
2842
+ "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
2843
+ "dependencies": {
2844
+ "toggle-selection": "^1.0.6"
2845
+ }
2846
+ },
2847
  "node_modules/create-require": {
2848
  "version": "1.1.1",
2849
  "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
 
5571
  "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
5572
  }
5573
  },
5574
+ "node_modules/react-copy-to-clipboard": {
5575
+ "version": "5.1.0",
5576
+ "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz",
5577
+ "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==",
5578
+ "dependencies": {
5579
+ "copy-to-clipboard": "^3.3.1",
5580
+ "prop-types": "^15.8.1"
5581
+ },
5582
+ "peerDependencies": {
5583
+ "react": "^15.3.0 || 16 || 17 || 18"
5584
+ }
5585
+ },
5586
  "node_modules/react-dom": {
5587
  "version": "18.2.0",
5588
  "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
 
6517
  "node": ">=8.0"
6518
  }
6519
  },
6520
+ "node_modules/toggle-selection": {
6521
+ "version": "1.0.6",
6522
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
6523
+ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
6524
+ },
6525
  "node_modules/ts-interface-checker": {
6526
  "version": "0.1.13",
6527
  "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
package.json CHANGED
@@ -49,6 +49,7 @@
49
  "qs": "^6.11.2",
50
  "react": "18.2.0",
51
  "react-circular-progressbar": "^2.1.0",
 
52
  "react-dom": "18.2.0",
53
  "react-icons": "^4.12.0",
54
  "react-smooth-scroll-hook": "^1.3.4",
@@ -73,6 +74,7 @@
73
  "devDependencies": {
74
  "@types/proper-lockfile": "^4.1.2",
75
  "@types/qs": "^6.9.7",
 
76
  "@types/react-virtualized": "^9.21.22",
77
  "@types/sbd": "^1.0.3",
78
  "daisyui": "^3.7.4"
 
49
  "qs": "^6.11.2",
50
  "react": "18.2.0",
51
  "react-circular-progressbar": "^2.1.0",
52
+ "react-copy-to-clipboard": "^5.1.0",
53
  "react-dom": "18.2.0",
54
  "react-icons": "^4.12.0",
55
  "react-smooth-scroll-hook": "^1.3.4",
 
74
  "devDependencies": {
75
  "@types/proper-lockfile": "^4.1.2",
76
  "@types/qs": "^6.9.7",
77
+ "@types/react-copy-to-clipboard": "^5.0.7",
78
  "@types/react-virtualized": "^9.21.22",
79
  "@types/sbd": "^1.0.3",
80
  "daisyui": "^3.7.4"
src/app/views/public-video-view/index.tsx CHANGED
@@ -1,7 +1,10 @@
1
  "use client"
2
 
3
- import { useEffect } from "react"
4
  import { RiCheckboxCircleFill } from "react-icons/ri"
 
 
 
5
 
6
  import { useStore } from "@/app/state/useStore"
7
  import { cn } from "@/lib/utils"
@@ -14,6 +17,8 @@ export function PublicVideoView() {
14
 
15
  const videoId = `${video?.id || ""}`
16
 
 
 
17
  // we inject the current videoId in the URL, if it's not already present
18
  // this is a hack for Hugging Face iframes
19
  useEffect(() => {
@@ -32,6 +37,13 @@ export function PublicVideoView() {
32
  }
33
  }, [videoId])
34
 
 
 
 
 
 
 
 
35
  if (!video) { return null }
36
 
37
  return (
@@ -60,42 +72,95 @@ export function PublicVideoView() {
60
  {/** VIDEO TOOLBAR - HORIZONTAL */}
61
  <div className={cn(
62
  `flex flex-row`,
63
- `items-center`
 
 
64
  )}>
65
- {/** CHANNEL LOGO - VERTICAL */}
66
  <div className={cn(
67
- `flex flex-col`,
68
- `mr-3`
69
  )}>
70
- <div className="flex w-10 rounded-full overflow-hidden">
71
- <img
72
- src="huggingface-avatar.jpeg"
73
- />
 
 
 
 
 
 
74
  </div>
75
- </div>
76
 
77
- {/** CHANNEL INFO - VERTICAL */}
78
- <div className={cn(
79
- `flex flex-col`
80
- )}>
81
  <div className={cn(
82
- `flex flex-row items-center`,
83
- `text-zinc-100 text-base font-medium space-x-1`,
84
  )}>
85
- <div>{video.channel.label}</div>
86
- <div className="text-sm text-neutral-400"><RiCheckboxCircleFill className="" /></div>
 
 
 
 
 
 
 
 
 
 
 
 
87
  </div>
 
 
 
 
 
 
 
 
 
88
  <div className={cn(
89
- `flex flex-row items-center`,
90
- `text-neutral-400 text-xs font-normal space-x-1`,
91
- )}>
92
- <div>0 followers</div>
93
- <div></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  </div>
95
  </div>
96
 
97
  </div>
98
 
 
 
 
 
 
 
 
 
 
99
  </div>
100
  <div className={cn(
101
  `sm:w-56 md:w-96`,
 
1
  "use client"
2
 
3
+ import { useEffect, useState } from "react"
4
  import { RiCheckboxCircleFill } from "react-icons/ri"
5
+ import { PiShareFatLight } from "react-icons/pi"
6
+ import CopyToClipboard from "react-copy-to-clipboard"
7
+ import { LuCopyCheck } from "react-icons/lu"
8
 
9
  import { useStore } from "@/app/state/useStore"
10
  import { cn } from "@/lib/utils"
 
17
 
18
  const videoId = `${video?.id || ""}`
19
 
20
+ const [copied, setCopied] = useState<boolean>(false)
21
+
22
  // we inject the current videoId in the URL, if it's not already present
23
  // this is a hack for Hugging Face iframes
24
  useEffect(() => {
 
37
  }
38
  }, [videoId])
39
 
40
+ useEffect(() => {
41
+ if (copied) {
42
+ setTimeout(() => {
43
+ setCopied(false)
44
+ }, 2000)
45
+ }
46
+ }, [copied])
47
  if (!video) { return null }
48
 
49
  return (
 
72
  {/** VIDEO TOOLBAR - HORIZONTAL */}
73
  <div className={cn(
74
  `flex flex-row`,
75
+ `items-center`,
76
+ `justify-between`,
77
+ `mb-4`
78
  )}>
79
+ {/** LEFT PART FO THE TOOLBARR */}
80
  <div className={cn(
81
+ `flex flex-row`,
82
+ `items-center`
83
  )}>
84
+ {/** CHANNEL LOGO - VERTICAL */}
85
+ <div className={cn(
86
+ `flex flex-col`,
87
+ `mr-3`
88
+ )}>
89
+ <div className="flex w-10 rounded-full overflow-hidden">
90
+ <img
91
+ src="huggingface-avatar.jpeg"
92
+ />
93
+ </div>
94
  </div>
 
95
 
96
+ {/** CHANNEL INFO - VERTICAL */}
 
 
 
97
  <div className={cn(
98
+ `flex flex-col`
 
99
  )}>
100
+ <div className={cn(
101
+ `flex flex-row items-center`,
102
+ `text-zinc-100 text-base font-medium space-x-1`,
103
+ )}>
104
+ <div>{video.channel.label}</div>
105
+ <div className="text-sm text-neutral-400"><RiCheckboxCircleFill className="" /></div>
106
+ </div>
107
+ <div className={cn(
108
+ `flex flex-row items-center`,
109
+ `text-neutral-400 text-xs font-normal space-x-1`,
110
+ )}>
111
+ <div>0 followers</div>
112
+ <div></div>
113
+ </div>
114
  </div>
115
+ </div>
116
+
117
+ {/** RIGHT PART FO THE TOOLBAR */}
118
+ <div className={cn(
119
+ `flex flex-row`,
120
+ `items-center`,
121
+ `space-x-2`
122
+ )}>
123
+ {/* SHARE */}
124
  <div className={cn(
125
+ `flex flex-row`,
126
+ `items-center`
127
+ )}>
128
+ <CopyToClipboard
129
+ text={`https://huggingface.co/spaces/jbilcke-hf/ai-tube?v=${video.id}`}
130
+ onCopy={() => setCopied(true)}>
131
+ <div className={cn(
132
+ `flex flex-row space-x-2 pl-3 pr-4 h-9`,
133
+ `items-center justify-center text-center`,
134
+ `rounded-2xl`,
135
+ `cursor-pointer`,
136
+ `bg-neutral-700/50 hover:bg-neutral-700/90 text-zinc-100`
137
+ )}>
138
+ <div className="flex items-center justify-center pt-0.5">
139
+ {
140
+ copied ? <LuCopyCheck className="w-4 h-4" />
141
+ : <PiShareFatLight className="w-5 h-5" />
142
+ }
143
+ </div>
144
+ <div className="text-sm font-medium">
145
+ {
146
+ copied ? "Link copied!" : "Share video"
147
+ }</div>
148
+ </div>
149
+ </CopyToClipboard>
150
  </div>
151
  </div>
152
 
153
  </div>
154
 
155
+ {/** VIDEO DESCRIPTION - VERTICAL */}
156
+ <div className={cn(
157
+ `flex flex-col p-3`,
158
+ `rounded-xl`,
159
+ `bg-neutral-700/50`,
160
+ `text-sm`
161
+ )}>
162
+ <p>{video.description}</p>
163
+ </div>
164
  </div>
165
  <div className={cn(
166
  `sm:w-56 md:w-96`,