@linktr.ee/messaging-react 1.30.0 → 1.30.1-rc-1776660256
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Creator-77XnrIxc.js → Creator-C8EwYYcW.js} +83 -83
- package/dist/Creator-C8EwYYcW.js.map +1 -0
- package/dist/{MediaPlayer-Bf-xPB8Z.js → MediaPlayer-dT6eJALR.js} +60 -62
- package/dist/MediaPlayer-dT6eJALR.js.map +1 -0
- package/dist/{Visitor-C9HSYm3D.js → Visitor-BACiehsg.js} +81 -78
- package/dist/Visitor-BACiehsg.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/CustomMessage/index.tsx +1 -1
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +41 -41
- package/src/components/LockedAttachment/components/Creator.tsx +41 -41
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +3 -8
- package/src/components/LockedAttachment/components/Visitor.tsx +49 -39
- package/src/components/LockedAttachment/index.tsx +1 -1
- package/src/components/LockedAttachment/types.ts +2 -2
- package/src/types.ts +4 -1
- package/dist/Creator-77XnrIxc.js.map +0 -1
- package/dist/MediaPlayer-Bf-xPB8Z.js.map +0 -1
- package/dist/Visitor-C9HSYm3D.js.map +0 -1
|
@@ -25,11 +25,12 @@ export interface VisitorCardProps extends LockedAttachmentBaseProps {
|
|
|
25
25
|
*/
|
|
26
26
|
onUnlock?: () => Promise<LockedAttachmentSource>
|
|
27
27
|
/** Called when the visitor clicks Download on an unlocked card. */
|
|
28
|
-
onDownload?: () => void
|
|
28
|
+
onDownload?: () => void
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType =>
|
|
32
|
-
paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon
|
|
31
|
+
const getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType => {
|
|
32
|
+
return paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon
|
|
33
|
+
}
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
interface LockOverlayProps {
|
|
@@ -48,18 +49,18 @@ const LockOverlay: React.FC<LockOverlayProps> = (props) => {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
interface LockedPreviewProps {
|
|
51
|
-
|
|
52
|
+
thumbnailUrl?: string
|
|
52
53
|
mimeType: string
|
|
53
54
|
LockIcon: React.ElementType
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const LockedPreview: React.FC<LockedPreviewProps> = (props) => {
|
|
57
|
-
const {
|
|
58
|
+
const { thumbnailUrl, mimeType, LockIcon } = props
|
|
58
59
|
return (
|
|
59
60
|
<div className="relative aspect-video overflow-hidden bg-black/5">
|
|
60
|
-
{
|
|
61
|
+
{thumbnailUrl ? (
|
|
61
62
|
<img
|
|
62
|
-
src={
|
|
63
|
+
src={thumbnailUrl}
|
|
63
64
|
alt=""
|
|
64
65
|
className="absolute inset-0 h-full w-full object-cover"
|
|
65
66
|
/>
|
|
@@ -78,8 +79,8 @@ const LockedPreview: React.FC<LockedPreviewProps> = (props) => {
|
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
interface ImagePreviewProps {
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
sourceUrl?: string
|
|
83
|
+
thumbnailUrl?: string
|
|
83
84
|
mimeType: string
|
|
84
85
|
title?: string
|
|
85
86
|
paymentStatus?: PaymentStatus
|
|
@@ -87,17 +88,17 @@ interface ImagePreviewProps {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
|
|
90
|
-
const {
|
|
91
|
+
const { sourceUrl, thumbnailUrl, mimeType, title, paymentStatus, isLocked } = props
|
|
91
92
|
const [sourceReady, setSourceReady] = useState(false)
|
|
92
93
|
|
|
93
94
|
useEffect(() => {
|
|
94
95
|
setSourceReady(false)
|
|
95
|
-
}, [
|
|
96
|
+
}, [sourceUrl])
|
|
96
97
|
|
|
97
98
|
if (isLocked) {
|
|
98
99
|
return (
|
|
99
100
|
<LockedPreview
|
|
100
|
-
|
|
101
|
+
thumbnailUrl={thumbnailUrl}
|
|
101
102
|
mimeType={mimeType}
|
|
102
103
|
LockIcon={getLockIcon(paymentStatus)}
|
|
103
104
|
/>
|
|
@@ -107,7 +108,7 @@ const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
|
|
|
107
108
|
return (
|
|
108
109
|
<div className="relative overflow-hidden bg-black/5">
|
|
109
110
|
<img
|
|
110
|
-
src={
|
|
111
|
+
src={sourceUrl}
|
|
111
112
|
alt={title}
|
|
112
113
|
className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}
|
|
113
114
|
onLoad={() => setSourceReady(true)}
|
|
@@ -117,19 +118,19 @@ const ImagePreview: React.FC<ImagePreviewProps> = (props) => {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
interface DocumentPreviewProps {
|
|
120
|
-
|
|
121
|
+
thumbnailUrl?: string
|
|
121
122
|
mimeType: string
|
|
122
123
|
paymentStatus?: PaymentStatus
|
|
123
124
|
isLocked: boolean
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
const DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {
|
|
127
|
-
const {
|
|
128
|
+
const { thumbnailUrl, mimeType, paymentStatus, isLocked } = props
|
|
128
129
|
return (
|
|
129
130
|
<div className="relative aspect-video overflow-hidden bg-black/5">
|
|
130
|
-
{
|
|
131
|
+
{thumbnailUrl ? (
|
|
131
132
|
<img
|
|
132
|
-
src={
|
|
133
|
+
src={thumbnailUrl}
|
|
133
134
|
alt=""
|
|
134
135
|
className="absolute inset-0 h-full w-full object-cover"
|
|
135
136
|
/>
|
|
@@ -147,25 +148,25 @@ const DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
interface MediaPreviewProps {
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
sourceUrl?: string
|
|
152
|
+
thumbnailUrl?: string
|
|
152
153
|
mimeType: string
|
|
153
154
|
paymentStatus?: PaymentStatus
|
|
154
155
|
isLocked: boolean
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
const MediaPreview: React.FC<MediaPreviewProps> = (props) => {
|
|
158
|
-
const {
|
|
159
|
+
const { sourceUrl, thumbnailUrl, mimeType, paymentStatus, isLocked } = props
|
|
159
160
|
if (isLocked) {
|
|
160
161
|
return (
|
|
161
162
|
<LockedPreview
|
|
162
|
-
|
|
163
|
+
thumbnailUrl={thumbnailUrl}
|
|
163
164
|
mimeType={mimeType}
|
|
164
165
|
LockIcon={getLockIcon(paymentStatus)}
|
|
165
166
|
/>
|
|
166
167
|
)
|
|
167
168
|
}
|
|
168
|
-
return <MediaPlayer source={
|
|
169
|
+
return <MediaPlayer source={sourceUrl!} mimeType={mimeType} poster={thumbnailUrl} />
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
|
|
@@ -180,13 +181,14 @@ const LoadingDots = () => (
|
|
|
180
181
|
interface CardActionsProps {
|
|
181
182
|
isLocked: boolean
|
|
182
183
|
unlockLoading: boolean
|
|
183
|
-
|
|
184
|
+
sourceUrl?: string
|
|
185
|
+
redeemUrl?: string
|
|
184
186
|
onUnlock?: () => void
|
|
185
187
|
onDownload?: () => void
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
const CardActions: React.FC<CardActionsProps> = (props) => {
|
|
189
|
-
const { isLocked, unlockLoading,
|
|
191
|
+
const { isLocked, unlockLoading, sourceUrl, redeemUrl, onUnlock, onDownload } = props
|
|
190
192
|
|
|
191
193
|
if (isLocked && onUnlock) {
|
|
192
194
|
return (
|
|
@@ -208,10 +210,12 @@ const CardActions: React.FC<CardActionsProps> = (props) => {
|
|
|
208
210
|
)
|
|
209
211
|
}
|
|
210
212
|
|
|
211
|
-
if (!isLocked && onDownload &&
|
|
213
|
+
if (!isLocked && onDownload && sourceUrl) {
|
|
212
214
|
return (
|
|
213
215
|
<a
|
|
214
|
-
href={
|
|
216
|
+
href={redeemUrl ?? sourceUrl}
|
|
217
|
+
target="_blank"
|
|
218
|
+
rel="noopener noreferrer"
|
|
215
219
|
onClick={onDownload}
|
|
216
220
|
className="mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]"
|
|
217
221
|
>
|
|
@@ -229,22 +233,26 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
229
233
|
const {
|
|
230
234
|
title,
|
|
231
235
|
amountText,
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
thumbnailUrl,
|
|
237
|
+
sourceUrl: sourceProp,
|
|
234
238
|
mimeType = 'application/octet-stream',
|
|
235
239
|
detail,
|
|
236
240
|
onUnlock,
|
|
237
241
|
onDownload,
|
|
238
242
|
paymentStatus,
|
|
239
243
|
} = props
|
|
240
|
-
const [
|
|
244
|
+
const [sourceUrl, setSourceUrl] = useState(sourceProp)
|
|
245
|
+
const [redeemUrl, setRedeemUrl] = useState<string | undefined>(undefined)
|
|
241
246
|
const [unlockLoading, setUnlockLoading] = useState(false)
|
|
242
247
|
|
|
243
248
|
useEffect(() => {
|
|
244
|
-
if (sourceProp !== undefined)
|
|
249
|
+
if (sourceProp !== undefined) {
|
|
250
|
+
setSourceUrl(sourceProp)
|
|
251
|
+
setRedeemUrl(undefined)
|
|
252
|
+
}
|
|
245
253
|
}, [sourceProp])
|
|
246
254
|
|
|
247
|
-
const isLocked =
|
|
255
|
+
const isLocked = sourceUrl === undefined
|
|
248
256
|
const sourceType = getSourceType(mimeType)
|
|
249
257
|
|
|
250
258
|
const handleUnlock = async () => {
|
|
@@ -252,7 +260,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
252
260
|
setUnlockLoading(true)
|
|
253
261
|
try {
|
|
254
262
|
const result = await onUnlock()
|
|
255
|
-
|
|
263
|
+
setSourceUrl(result.sourceUrl)
|
|
264
|
+
setRedeemUrl(result.redeemUrl)
|
|
256
265
|
} catch (err) {
|
|
257
266
|
if (isDevBuild()) console.debug('[LockedAttachment] onUnlock failed', err)
|
|
258
267
|
} finally {
|
|
@@ -264,8 +273,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
264
273
|
if (sourceType === 'image') {
|
|
265
274
|
mediaPreview = (
|
|
266
275
|
<ImagePreview
|
|
267
|
-
|
|
268
|
-
|
|
276
|
+
sourceUrl={sourceUrl}
|
|
277
|
+
thumbnailUrl={thumbnailUrl}
|
|
269
278
|
mimeType={mimeType}
|
|
270
279
|
title={title}
|
|
271
280
|
paymentStatus={paymentStatus}
|
|
@@ -275,7 +284,7 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
275
284
|
} else if (sourceType === 'document') {
|
|
276
285
|
mediaPreview = (
|
|
277
286
|
<DocumentPreview
|
|
278
|
-
|
|
287
|
+
thumbnailUrl={thumbnailUrl}
|
|
279
288
|
mimeType={mimeType}
|
|
280
289
|
paymentStatus={paymentStatus}
|
|
281
290
|
isLocked={isLocked}
|
|
@@ -284,8 +293,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
284
293
|
} else {
|
|
285
294
|
mediaPreview = (
|
|
286
295
|
<MediaPreview
|
|
287
|
-
|
|
288
|
-
|
|
296
|
+
sourceUrl={sourceUrl}
|
|
297
|
+
thumbnailUrl={thumbnailUrl}
|
|
289
298
|
mimeType={mimeType}
|
|
290
299
|
paymentStatus={paymentStatus}
|
|
291
300
|
isLocked={isLocked}
|
|
@@ -294,7 +303,7 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
294
303
|
}
|
|
295
304
|
|
|
296
305
|
return (
|
|
297
|
-
<div className="w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-
|
|
306
|
+
<div className="w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]">
|
|
298
307
|
{mediaPreview}
|
|
299
308
|
<div className="px-4 pb-3 pt-3">
|
|
300
309
|
<p className="mb-1.5 truncate text-base font-medium text-black">
|
|
@@ -333,7 +342,8 @@ const VisitorCard: React.FC<VisitorCardProps> = (props) => {
|
|
|
333
342
|
<CardActions
|
|
334
343
|
isLocked={isLocked}
|
|
335
344
|
unlockLoading={unlockLoading}
|
|
336
|
-
|
|
345
|
+
sourceUrl={sourceUrl}
|
|
346
|
+
redeemUrl={redeemUrl}
|
|
337
347
|
onUnlock={onUnlock ? handleUnlock : undefined}
|
|
338
348
|
onDownload={onDownload}
|
|
339
349
|
/>
|
|
@@ -8,7 +8,7 @@ const VisitorCardLazy = React.lazy(() => import('./components/Visitor'))
|
|
|
8
8
|
|
|
9
9
|
const LockedAttachmentFallback = () => (
|
|
10
10
|
<div
|
|
11
|
-
className="w-[280px] min-h-[200px] animate-pulse rounded-[24px] bg-black/[0.06] shadow-[
|
|
11
|
+
className="w-[280px] min-h-[200px] animate-pulse rounded-[24px] bg-black/[0.06] shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_4px_8px_rgba(0,0,0,0.06)]"
|
|
12
12
|
aria-hidden
|
|
13
13
|
/>
|
|
14
14
|
)
|
|
@@ -3,8 +3,8 @@ import type { PaymentStatus } from '../../stream-custom-data'
|
|
|
3
3
|
export interface LockedAttachmentBaseProps {
|
|
4
4
|
title?: string
|
|
5
5
|
mimeType?: string
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
thumbnailUrl?: string
|
|
7
|
+
sourceUrl?: string
|
|
8
8
|
detail?: string
|
|
9
9
|
amountText?: string
|
|
10
10
|
paymentStatus?: PaymentStatus
|
package/src/types.ts
CHANGED
|
@@ -118,7 +118,10 @@ export interface ChannelListProps {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export interface LockedAttachmentSource {
|
|
121
|
-
|
|
121
|
+
/** Proxied URL used by the media player for in-app playback. */
|
|
122
|
+
sourceUrl: string
|
|
123
|
+
/** URL opened when the visitor clicks Download — may be a file or a web destination. */
|
|
124
|
+
redeemUrl?: string
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
/**
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Creator-77XnrIxc.js","sources":["../src/components/LockedAttachment/components/Creator.tsx"],"sourcesContent":["import {\n CheckCircleIcon,\n EyeIcon,\n EyeSlashIcon,\n LockIcon,\n LockOpenIcon,\n PauseIcon,\n PlayIcon,\n XIcon,\n} from '@phosphor-icons/react'\nimport classNames from 'classnames'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { LockedAttachmentBaseProps } from '../types'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType } from '../utils/mimeType'\n\nimport MediaPlayer from './MediaPlayer'\n\nexport interface CreatorCardProps extends LockedAttachmentBaseProps {\n isPreview?: boolean\n placeholderTitle?: string\n placeholderAmountText?: string\n onDismiss?: () => void\n}\n\ninterface CloseButtonProps {\n onClose: () => void\n}\n\nconst CloseButton: React.FC<CloseButtonProps> = (props) => {\n const { onClose } = props\n return (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"absolute left-3 top-3 z-40 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\"\n aria-label=\"Close preview\"\n >\n <EyeIcon className=\"size-4\" weight=\"fill\" />\n </button>\n )\n}\n\ninterface CollapsedThumbnailProps {\n thumbnail?: string\n mimeType: string\n overlayIcon?: React.ElementType\n darkOverlay?: boolean\n onClick?: () => void\n}\n\nconst CollapsedThumbnail: React.FC<CollapsedThumbnailProps> = (props) => {\n const { thumbnail, mimeType, overlayIcon: OverlayIcon, darkOverlay, onClick } = props\n return (\n <button\n type=\"button\"\n disabled={!onClick}\n className={classNames(\n 'relative aspect-video block w-full overflow-hidden border-0 bg-black/5 p-0 text-left appearance-none',\n { 'cursor-pointer': !!onClick, 'cursor-default': !onClick }\n )}\n onClick={onClick}\n aria-label={OverlayIcon ? 'Toggle preview' : undefined}\n >\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {darkOverlay && (\n <div className=\"pointer-events-none absolute inset-0 bg-black/30\" />\n )}\n {OverlayIcon && (\n <div className=\"pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\">\n <OverlayIcon className=\"size-4\" weight=\"fill\" />\n </div>\n )}\n </button>\n )\n}\n\n\ninterface AudioPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n}\n\nconst AudioPreview: React.FC<AudioPreviewProps> = (props) => {\n const { source, thumbnail, mimeType } = props\n const [playing, setPlaying] = useState(false)\n const [played, setPlayed] = useState(0)\n const [seeking, setSeeking] = useState(false)\n const audioRef = useRef<HTMLAudioElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const rafRef = useRef<number | null>(null)\n\n useEffect(() => {\n const el = audioRef.current\n if (!el) return\n if (playing) {\n void el.play().catch(() => setPlaying(false))\n } else {\n el.pause()\n }\n }, [playing])\n\n useEffect(() => {\n if (!playing) {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n return\n }\n const tick = () => {\n const el = audioRef.current\n if (el && el.duration && !seeking) setPlayed(el.currentTime / el.duration)\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n return () => {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n }\n }, [playing, seeking])\n\n const [audioReady, setAudioReady] = useState(false)\n\n useEffect(() => {\n setPlaying(false)\n setPlayed(0)\n setAudioReady(false)\n }, [source])\n\n const getFraction = useCallback(\n (e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) => {\n const track = trackRef.current\n if (!track) return 0\n const clientX =\n 'touches' in e\n ? (e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0)\n : e.clientX\n const rect = track.getBoundingClientRect()\n return Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))\n },\n []\n )\n\n const seekTo = useCallback((fraction: number) => {\n const el = audioRef.current\n if (el && el.duration) el.currentTime = fraction * el.duration\n }, [])\n\n useEffect(() => {\n if (!seeking) return\n const onMove = (e: MouseEvent | TouchEvent) => {\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }\n const onUp = (e: MouseEvent | TouchEvent) => {\n setSeeking(false)\n seekTo(getFraction(e))\n }\n window.addEventListener('mousemove', onMove)\n window.addEventListener('mouseup', onUp)\n window.addEventListener('touchmove', onMove, { passive: true })\n window.addEventListener('touchend', onUp)\n return () => {\n window.removeEventListener('mousemove', onMove)\n window.removeEventListener('mouseup', onUp)\n window.removeEventListener('touchmove', onMove)\n window.removeEventListener('touchend', onUp)\n }\n }, [seeking, getFraction, seekTo])\n\n const toggle = useCallback(() => setPlaying((p) => !p), [])\n\n return (\n <div className=\"relative\">\n {source && (\n <audio\n ref={audioRef}\n src={source}\n loop\n onCanPlay={() => setAudioReady(true)}\n onEnded={() => {\n setPlaying(false)\n setPlayed(0)\n }}\n >\n <track kind=\"captions\" />\n </audio>\n )}\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={source && audioReady ? (playing ? PauseIcon : PlayIcon) : undefined}\n onClick={source && audioReady ? toggle : undefined}\n />\n {source && audioReady && (\n <div className=\"absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent\">\n <div\n ref={trackRef}\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={Math.round(played * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={(e) => {\n e.stopPropagation()\n setSeeking(true)\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }}\n onTouchStart={(e) => {\n e.stopPropagation()\n setSeeking(true)\n const f = getFraction(e)\n setPlayed(f)\n seekTo(f)\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div className=\"w-full overflow-hidden rounded-full bg-white/30 h-1\">\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${Math.round(played * 100)}%` }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\ninterface VideoPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n}\n\nconst VideoPreview: React.FC<VideoPreviewProps> = (props) => {\n const { source, thumbnail, mimeType } = props\n const [expanded, setExpanded] = useState(false)\n const collapse = () => setExpanded(false)\n\n useEffect(() => {\n setExpanded(false)\n }, [source])\n\n if (!source) {\n return <CollapsedThumbnail thumbnail={thumbnail} mimeType={mimeType} />\n }\n\n return (\n <div\n className={classNames('relative overflow-hidden', {\n 'aspect-video': !expanded,\n })}\n >\n <MediaPlayer\n source={source}\n mimeType={mimeType}\n poster={thumbnail}\n playing={expanded}\n loop\n controls={false}\n showProgress\n onContainerClick={collapse}\n muted\n />\n {!expanded && (\n <button\n type=\"button\"\n className=\"absolute inset-0 block cursor-pointer border-0 p-0 text-left appearance-none\"\n onClick={() => setExpanded(true)}\n aria-label=\"Expand video preview\"\n >\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n <div className=\"pointer-events-none absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\">\n <EyeSlashIcon className=\"size-4\" weight=\"fill\" />\n </div>\n </button>\n )}\n {expanded && <CloseButton onClose={collapse} />}\n </div>\n )\n}\n\ninterface ImagePreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n title?: string\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { source, thumbnail, mimeType, title } = props\n const [expanded, setExpanded] = useState(false)\n const collapse = () => setExpanded(false)\n\n useEffect(() => {\n setExpanded(false)\n }, [source])\n\n if (expanded && source) {\n return (\n <div className=\"relative\">\n <button\n type=\"button\"\n className=\"block w-full cursor-pointer border-0 p-0 text-left appearance-none\"\n onClick={collapse}\n aria-label=\"Close preview\"\n >\n <img src={source} alt={title ?? ''} className=\"block w-full\" />\n </button>\n <CloseButton onClose={collapse} />\n </div>\n )\n }\n\n return (\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={source ? EyeSlashIcon : undefined}\n onClick={source ? () => setExpanded(true) : undefined}\n />\n )\n}\n\n\nconst CreatorCard: React.FC<CreatorCardProps> = (props) => {\n const {\n title,\n mimeType = 'application/octet-stream',\n thumbnail,\n source,\n detail,\n amountText,\n placeholderTitle = 'Attachment title',\n placeholderAmountText,\n paymentStatus,\n onDismiss,\n isPreview = false,\n } = props\n const sourceType = getSourceType(mimeType)\n const displayAmountText = amountText ?? placeholderAmountText\n const isPlaceholderAmount = !amountText && !!placeholderAmountText\n\n let mediaPreview: React.ReactNode\n if (isPreview && sourceType === 'audio') {\n mediaPreview = (\n <AudioPreview source={source} thumbnail={thumbnail} mimeType={mimeType} />\n )\n } else if (isPreview && sourceType === 'video') {\n mediaPreview = (\n <VideoPreview source={source} thumbnail={thumbnail} mimeType={mimeType} />\n )\n } else if (isPreview && sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n title={title}\n />\n )\n } else {\n const lockedOverlayIcon = onDismiss\n ? undefined\n : paymentStatus === 'paid'\n ? LockOpenIcon\n : LockIcon\n mediaPreview = (\n <CollapsedThumbnail\n thumbnail={thumbnail}\n mimeType={mimeType}\n overlayIcon={lockedOverlayIcon}\n darkOverlay\n />\n )\n }\n\n return (\n <div className=\"relative w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-card\">\n {onDismiss && (\n <button\n type=\"button\"\n onClick={onDismiss}\n className=\"absolute right-3 top-3 z-50 flex size-8 items-center justify-center rounded-full bg-black/60 text-white\"\n aria-label=\"Dismiss attachment\"\n >\n <XIcon className=\"size-4\" weight=\"bold\" />\n </button>\n )}\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p\n className={classNames('mb-1.5 truncate text-base font-medium', {\n 'text-black/30': !title,\n 'text-black': !!title,\n })}\n >\n {title || placeholderTitle}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail && (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n )}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : (\n displayAmountText && (\n <>\n <span\n className={classNames('text-xs font-medium', {\n 'text-black/30': isPlaceholderAmount,\n 'text-black/55': !isPlaceholderAmount,\n })}\n >\n •\n </span>\n <span\n className={classNames('text-xs font-medium', {\n 'text-black/30': isPlaceholderAmount,\n 'text-black/55': !isPlaceholderAmount,\n })}\n >\n {displayAmountText}\n </span>\n </>\n )\n )}\n </div>\n </div>\n </div>\n )\n}\n\nexport default CreatorCard\n"],"names":["CloseButton","props","onClose","jsx","EyeIcon","CollapsedThumbnail","thumbnail","mimeType","OverlayIcon","darkOverlay","onClick","jsxs","classNames","AudioPreview","source","playing","setPlaying","useState","played","setPlayed","seeking","setSeeking","audioRef","useRef","trackRef","rafRef","useEffect","el","tick","audioReady","setAudioReady","getFraction","useCallback","e","track","clientX","_a","_b","rect","seekTo","fraction","onMove","f","onUp","toggle","p","PauseIcon","PlayIcon","VideoPreview","expanded","setExpanded","collapse","MediaPlayer","EyeSlashIcon","ImagePreview","title","CreatorCard","detail","amountText","placeholderTitle","placeholderAmountText","paymentStatus","onDismiss","isPreview","sourceType","getSourceType","displayAmountText","isPlaceholderAmount","mediaPreview","LockOpenIcon","LockIcon","XIcon","renderTypeIcon","Fragment","CheckCircleIcon"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MediaPlayer-Bf-xPB8Z.js","sources":["../src/components/LockedAttachment/utils/mimeType.ts","../src/components/LockedAttachment/utils/icons.ts","../src/components/LockedAttachment/components/MediaPlayer.tsx"],"sourcesContent":["export type AttachmentSourceType = 'image' | 'audio' | 'video' | 'document'\n\nexport type DocumentIconType =\n | 'pdf'\n | 'doc'\n | 'xls'\n | 'csv'\n | 'ppt'\n | 'zip'\n | 'text'\n | 'markdown'\n | 'generic'\n\nconst DOCUMENT_ICON_PATTERNS: Array<[RegExp, DocumentIconType]> = [\n [/pdf/, 'pdf'],\n [/wordprocessingml|msword|\\.doc/, 'doc'],\n [/spreadsheetml|ms-excel|\\.xls/, 'xls'],\n [/csv/, 'csv'],\n [/presentationml|ms-powerpoint|\\.ppt/, 'ppt'],\n [/zip|x-rar|x-7z|x-tar|x-gzip/, 'zip'],\n [/plain|rtf/, 'text'],\n [/markdown/, 'markdown'],\n]\n\nexport function getSourceType(mimeType: string): AttachmentSourceType {\n if (mimeType.startsWith('video/')) return 'video'\n if (mimeType.startsWith('audio/')) return 'audio'\n if (mimeType.startsWith('image/')) return 'image'\n return 'document'\n}\n\nexport function getDocumentIconType(mimeType: string): DocumentIconType {\n const match = DOCUMENT_ICON_PATTERNS.find(([pattern]) =>\n pattern.test(mimeType)\n )\n return match ? match[1] : 'generic'\n}\n","import {\n FileIcon,\n FileCsvIcon,\n FileDocIcon,\n FileMdIcon,\n FilePdfIcon,\n FilePptIcon,\n FileTextIcon,\n FileXlsIcon,\n FileZipIcon,\n ImageIcon,\n SpeakerHighIcon,\n VideoCameraIcon,\n IconProps,\n} from '@phosphor-icons/react'\nimport React from 'react'\n\nimport { getDocumentIconType, getSourceType } from './mimeType'\nimport type { AttachmentSourceType } from './mimeType'\n\nexport const MEDIA_TYPE_ICON: Record<AttachmentSourceType, React.ElementType> =\n {\n video: VideoCameraIcon,\n audio: SpeakerHighIcon,\n image: ImageIcon,\n document: FileIcon,\n }\n\nconst DOCUMENT_ICON_COMPONENT = {\n pdf: FilePdfIcon,\n doc: FileDocIcon,\n xls: FileXlsIcon,\n csv: FileCsvIcon,\n ppt: FilePptIcon,\n zip: FileZipIcon,\n text: FileTextIcon,\n markdown: FileMdIcon,\n generic: FileIcon,\n} as const\n\nexport function getTypeIcon(mimeType: string): React.ElementType {\n const sourceType = getSourceType(mimeType)\n if (sourceType !== 'document') return MEDIA_TYPE_ICON[sourceType]\n return DOCUMENT_ICON_COMPONENT[getDocumentIconType(mimeType)]\n}\n\n/** Use instead of `<TypeIcon />` where TypeIcon = getTypeIcon(mime) to satisfy react-hooks/static-components. */\nexport function renderTypeIcon(\n mimeType: string,\n props: IconProps\n): React.ReactElement {\n return React.createElement(getTypeIcon(mimeType), props)\n}\n","import { CircleNotchIcon, PauseIcon, PlayIcon } from '@phosphor-icons/react'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { isDevBuild } from '../../../utils/isDevBuild'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType, type AttachmentSourceType } from '../utils/mimeType'\n\nconst getPlayerBg = (sourceType: AttachmentSourceType, poster?: string) =>\n sourceType === 'audio' && !poster ? 'bg-black/5' : 'bg-black'\n\nfunction getClientXFromEvent(\n e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent\n): number {\n if ('touches' in e) {\n return e.touches[0]?.clientX ?? e.changedTouches[0]?.clientX ?? 0\n }\n return e.clientX\n}\n\nexport interface MediaPlayerProps {\n source: string\n mimeType: string\n poster?: string\n autoPlay?: boolean\n /** Controlled playing state. When provided, syncs to internal play/pause. */\n playing?: boolean\n loop?: boolean\n controls?: boolean\n showProgress?: boolean\n onContainerClick?: () => void\n /** When true, requests muted playback (helps autoplay policies on video). */\n muted?: boolean\n}\n\nconst MediaPlayer: React.FC<MediaPlayerProps> = ({\n source,\n mimeType,\n poster,\n autoPlay = false,\n playing: playingProp,\n loop = false,\n controls = true,\n showProgress = false,\n onContainerClick,\n muted = false,\n}) => {\n const sourceType = getSourceType(mimeType)\n const [playing, setPlaying] = useState(autoPlay)\n\n // Sync controlled playing prop to internal state\n const prevPlayingPropRef = useRef(playingProp)\n useEffect(() => {\n if (\n playingProp !== undefined &&\n playingProp !== prevPlayingPropRef.current\n ) {\n prevPlayingPropRef.current = playingProp\n setPlaying(playingProp)\n }\n }, [playingProp])\n const [played, setPlayed] = useState(0)\n const [seeking, setSeeking] = useState(false)\n const [scrubberHovered, setScrubberHovered] = useState(false)\n const [videoAspect, setVideoAspect] = useState<number | null>(null)\n const [buffering, setBuffering] = useState(false)\n /** True until the first canPlay fires for the current source — hides controls/spinner behind poster. */\n const [initialLoad, setInitialLoad] = useState(true)\n /** Set when autoplay/play() was rejected so user can start via gesture (no controls UI). */\n const [manualPlayRequired, setManualPlayRequired] = useState(false)\n const playerRef = useRef<HTMLMediaElement>(null)\n const trackRef = useRef<HTMLDivElement>(null)\n const rafRef = useRef<number | null>(null)\n\n useEffect(() => {\n setManualPlayRequired(false)\n setInitialLoad(true)\n }, [source])\n\n useEffect(() => {\n if (!playing) {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n return\n }\n const tick = () => {\n const el = playerRef.current\n if (el && el.duration && !seeking) setPlayed(el.currentTime / el.duration)\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n return () => {\n if (rafRef.current !== null) cancelAnimationFrame(rafRef.current)\n }\n }, [playing, seeking])\n\n // ReactPlayer v3 uses native HTML media elements and does not support a\n // declarative `playing` prop — playback must be driven imperatively.\n useEffect(() => {\n const el = playerRef.current\n if (!el) return\n if (playing) {\n void el.play().catch((err) => {\n setPlaying(false)\n setManualPlayRequired(true)\n if (isDevBuild()) {\n console.debug('[MediaPlayer] play() failed', err)\n }\n })\n } else {\n el.pause()\n }\n }, [playing])\n\n const startPlaybackFromGesture = useCallback(() => {\n setManualPlayRequired(false)\n setPlaying(true)\n }, [])\n\n const getFraction = useCallback(\n (e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) => {\n const track = trackRef.current\n if (!track) return 0\n const rect = track.getBoundingClientRect()\n return Math.max(\n 0,\n Math.min(1, (getClientXFromEvent(e) - rect.left) / rect.width)\n )\n },\n []\n )\n\n const seekTo = useCallback((fraction: number) => {\n const el = playerRef.current\n if (el && el.duration) el.currentTime = fraction * el.duration\n }, [])\n\n const handleTrackPointerDown = (\n e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>\n ) => {\n e.stopPropagation()\n setSeeking(true)\n const fraction = getFraction(e)\n setPlayed(fraction)\n seekTo(fraction)\n }\n\n useEffect(() => {\n if (!seeking) return\n const onMove = (e: MouseEvent | TouchEvent) => setPlayed(getFraction(e))\n const onUp = (e: MouseEvent | TouchEvent) => {\n setSeeking(false)\n seekTo(getFraction(e))\n }\n window.addEventListener('mousemove', onMove)\n window.addEventListener('mouseup', onUp)\n window.addEventListener('touchmove', onMove, { passive: true })\n window.addEventListener('touchend', onUp)\n return () => {\n window.removeEventListener('mousemove', onMove)\n window.removeEventListener('mouseup', onUp)\n window.removeEventListener('touchmove', onMove)\n window.removeEventListener('touchend', onUp)\n }\n }, [seeking, getFraction, seekTo])\n\n // Use natural aspect ratio once metadata loads, fall back to 16:9 before then.\n const aspectStyle = videoAspect\n ? { aspectRatio: String(videoAspect) }\n : undefined\n const aspectClass = !videoAspect ? ' aspect-video' : ''\n const scrubberPercent = Math.round(played * 100)\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n className={`relative cursor-pointer overflow-hidden ${getPlayerBg(sourceType, poster)}${aspectClass}`}\n style={aspectStyle}\n onClick={() => {\n if (manualPlayRequired) return\n if (onContainerClick) {\n onContainerClick()\n return\n }\n if (controls) setPlaying((p) => !p)\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n if (manualPlayRequired) return\n if (onContainerClick) {\n onContainerClick()\n return\n }\n if (controls) setPlaying((p) => !p)\n }}\n >\n {poster && (\n <img\n src={poster}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n )}\n {!poster && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {initialLoad && poster && (\n <div className=\"absolute inset-0 z-20\">\n <img src={poster} alt=\"\" className=\"h-full w-full object-cover\" />\n </div>\n )}\n <div className=\"absolute inset-0\">\n {sourceType === 'audio' ? (\n <audio\n ref={playerRef as React.RefObject<HTMLAudioElement>}\n src={source}\n loop={loop}\n muted={muted}\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => { setBuffering(false); setInitialLoad(false) }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </audio>\n ) : (\n <video\n ref={playerRef as React.RefObject<HTMLVideoElement>}\n src={source}\n poster={poster}\n loop={loop}\n muted={muted}\n playsInline\n style={{ width: '100%', height: '100%' }}\n onLoadStart={() => setBuffering(true)}\n onCanPlay={() => { setBuffering(false); setInitialLoad(false) }}\n onWaiting={() => setBuffering(true)}\n onPlay={() => setManualPlayRequired(false)}\n onLoadedMetadata={() => {\n const el = playerRef.current\n if (el instanceof HTMLVideoElement && el.videoWidth && el.videoHeight) {\n setVideoAspect(el.videoWidth / el.videoHeight)\n }\n }}\n onEnded={() => {\n if (!loop) {\n setPlaying(false)\n setPlayed(0)\n }\n }}\n >\n <track kind=\"captions\" />\n </video>\n )}\n </div>\n\n {buffering && !manualPlayRequired && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n <CircleNotchIcon\n className=\"size-8 animate-spin text-white/80\"\n weight=\"bold\"\n />\n </div>\n )}\n\n {manualPlayRequired && !controls && (\n <div\n className=\"absolute inset-0 z-30 flex cursor-pointer items-center justify-center bg-black/35\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"Play preview\"\n onClick={(e) => {\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n onKeyDown={(e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return\n e.preventDefault()\n e.stopPropagation()\n startPlaybackFromGesture()\n }}\n >\n <span className=\"flex size-16 items-center justify-center rounded-full bg-white/20 text-white backdrop-blur-sm\">\n <PlayIcon className=\"size-9 translate-x-0.5\" weight=\"fill\" />\n </span>\n </div>\n )}\n\n {showProgress && !controls && (\n <div className=\"absolute inset-x-0 bottom-0 px-3 pb-2.5 pt-6 bg-gradient-to-t from-black/40 to-transparent\">\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div className=\"w-full overflow-hidden rounded-full bg-white/30 h-1\">\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n </div>\n )}\n\n {controls && (\n <div className=\"absolute inset-x-0 bottom-0 flex items-center gap-2 bg-gradient-to-t from-black/60 to-transparent px-3 pb-2.5 pt-6 transition-all duration-200\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n setPlaying((p) => !p)\n }}\n className=\"shrink-0 text-white\"\n aria-label={playing ? 'Pause' : 'Play'}\n >\n {playing ? (\n <PauseIcon className=\"size-5\" weight=\"fill\" />\n ) : (\n <PlayIcon className=\"size-5 translate-x-px\" weight=\"fill\" />\n )}\n </button>\n\n <div\n role=\"slider\"\n aria-label=\"Playback position\"\n aria-valuenow={scrubberPercent}\n aria-valuemin={0}\n aria-valuemax={100}\n tabIndex={0}\n ref={trackRef}\n className=\"relative flex h-4 w-full cursor-pointer items-center\"\n onMouseDown={handleTrackPointerDown}\n onTouchStart={handleTrackPointerDown}\n onClick={(e) => e.stopPropagation()}\n onMouseEnter={() => setScrubberHovered(true)}\n onMouseLeave={() => setScrubberHovered(false)}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight') seekTo(Math.min(1, played + 0.05))\n if (e.key === 'ArrowLeft') seekTo(Math.max(0, played - 0.05))\n }}\n >\n <div\n className={`w-full overflow-hidden rounded-full bg-white/30 transition-all duration-200 ${scrubberHovered || seeking ? 'h-1.5' : 'h-1'}`}\n >\n <div\n className=\"h-full rounded-full bg-white\"\n style={{ width: `${scrubberPercent}%` }}\n />\n </div>\n <div\n className={`absolute size-3 -translate-x-1/2 rounded-full bg-white shadow transition-[opacity,transform] duration-200 ${scrubberHovered || seeking ? 'scale-100 opacity-100' : 'scale-0 opacity-0'}`}\n style={{ left: `${scrubberPercent}%` }}\n />\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default MediaPlayer\n"],"names":["DOCUMENT_ICON_PATTERNS","getSourceType","mimeType","getDocumentIconType","match","pattern","MEDIA_TYPE_ICON","VideoCameraIcon","SpeakerHighIcon","ImageIcon","FileIcon","DOCUMENT_ICON_COMPONENT","FilePdfIcon","FileDocIcon","FileXlsIcon","FileCsvIcon","FilePptIcon","FileZipIcon","FileTextIcon","FileMdIcon","getTypeIcon","sourceType","renderTypeIcon","props","React","getPlayerBg","poster","getClientXFromEvent","e","_a","_b","MediaPlayer","source","autoPlay","playingProp","loop","controls","showProgress","onContainerClick","muted","playing","setPlaying","useState","prevPlayingPropRef","useRef","useEffect","played","setPlayed","seeking","setSeeking","scrubberHovered","setScrubberHovered","videoAspect","setVideoAspect","buffering","setBuffering","initialLoad","setInitialLoad","manualPlayRequired","setManualPlayRequired","playerRef","trackRef","rafRef","tick","el","err","startPlaybackFromGesture","useCallback","getFraction","track","rect","seekTo","fraction","handleTrackPointerDown","onMove","onUp","aspectStyle","aspectClass","scrubberPercent","jsxs","p","jsx","CircleNotchIcon","PlayIcon","PauseIcon"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Visitor-C9HSYm3D.js","sources":["../src/components/LockedAttachment/components/Visitor.tsx"],"sourcesContent":["import {\n CheckCircleIcon,\n DownloadSimpleIcon,\n LockOpenIcon,\n LockSimpleIcon,\n} from '@phosphor-icons/react'\nimport React, { useEffect, useState } from 'react'\n\nimport { isDevBuild } from '../../../utils/isDevBuild'\nimport type {\n LockedAttachmentBaseProps,\n LockedAttachmentSource,\n PaymentStatus,\n} from '../types'\nimport { renderTypeIcon } from '../utils/icons'\nimport { getSourceType } from '../utils/mimeType'\n\nimport MediaPlayer from './MediaPlayer'\n\nexport interface VisitorCardProps extends LockedAttachmentBaseProps {\n /**\n * Called when the visitor clicks Unlock. Return the resolved source URL.\n * The component manages loading state and sets source internally on resolution.\n * Omit to hide the Unlock button.\n */\n onUnlock?: () => Promise<LockedAttachmentSource>\n /** Called when the visitor clicks Download on an unlocked card. */\n onDownload?: () => void \n}\n\nconst getLockIcon = (paymentStatus?: PaymentStatus): React.ElementType =>\n paymentStatus === 'paid' ? LockOpenIcon : LockSimpleIcon\n\n\ninterface LockOverlayProps {\n icon: React.ElementType\n}\n\nconst LockOverlay: React.FC<LockOverlayProps> = (props) => {\n const { icon: Icon } = props\n return (\n <div className=\"absolute inset-0 bg-black/30\">\n <div className=\"absolute left-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60\">\n <Icon className=\"size-4 text-white\" weight=\"fill\" />\n </div>\n </div>\n )\n}\n\ninterface LockedPreviewProps {\n thumbnail?: string\n mimeType: string\n LockIcon: React.ElementType\n}\n\nconst LockedPreview: React.FC<LockedPreviewProps> = (props) => {\n const { thumbnail, mimeType, LockIcon } = props\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n <LockOverlay icon={LockIcon} />\n </div>\n )\n}\n\n\ninterface ImagePreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n title?: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst ImagePreview: React.FC<ImagePreviewProps> = (props) => {\n const { source, thumbnail, mimeType, title, paymentStatus, isLocked } = props\n const [sourceReady, setSourceReady] = useState(false)\n\n useEffect(() => {\n setSourceReady(false)\n }, [source])\n\n if (isLocked) {\n return (\n <LockedPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n LockIcon={getLockIcon(paymentStatus)}\n />\n )\n }\n\n return (\n <div className=\"relative overflow-hidden bg-black/5\">\n <img\n src={source}\n alt={title}\n className={`block w-full transition-opacity duration-300 ${sourceReady ? 'opacity-100' : 'opacity-0'}`}\n onLoad={() => setSourceReady(true)}\n />\n </div>\n )\n}\n\ninterface DocumentPreviewProps {\n thumbnail?: string\n mimeType: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst DocumentPreview: React.FC<DocumentPreviewProps> = (props) => {\n const { thumbnail, mimeType, paymentStatus, isLocked } = props\n return (\n <div className=\"relative aspect-video overflow-hidden bg-black/5\">\n {thumbnail ? (\n <img\n src={thumbnail}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n {renderTypeIcon(mimeType, {\n className: 'size-12 text-black/20',\n weight: 'regular',\n })}\n </div>\n )}\n {isLocked && <LockOverlay icon={getLockIcon(paymentStatus)} />}\n </div>\n )\n}\n\ninterface MediaPreviewProps {\n source?: string\n thumbnail?: string\n mimeType: string\n paymentStatus?: PaymentStatus\n isLocked: boolean\n}\n\nconst MediaPreview: React.FC<MediaPreviewProps> = (props) => {\n const { source, thumbnail, mimeType, paymentStatus, isLocked } = props\n if (isLocked) {\n return (\n <LockedPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n LockIcon={getLockIcon(paymentStatus)}\n />\n )\n }\n return <MediaPlayer source={source!} mimeType={mimeType} poster={thumbnail} />\n}\n\n\nconst LoadingDots = () => (\n <span className=\"flex items-center gap-1\">\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.3s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce [animation-delay:-0.15s]\" />\n <span className=\"size-1 rounded-full bg-white animate-bounce\" />\n </span>\n)\n\ninterface CardActionsProps {\n isLocked: boolean\n unlockLoading: boolean\n source?: string\n onUnlock?: () => void\n onDownload?: () => void\n}\n\nconst CardActions: React.FC<CardActionsProps> = (props) => {\n const { isLocked, unlockLoading, source, onUnlock, onDownload } = props\n\n if (isLocked && onUnlock) {\n return (\n <button\n type=\"button\"\n onClick={onUnlock}\n disabled={unlockLoading}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none text-white hover:bg-[#2a2928] disabled:opacity-70\"\n >\n {unlockLoading ? (\n <LoadingDots />\n ) : (\n <>\n <LockSimpleIcon className=\"size-4\" weight=\"fill\" />\n Unlock\n </>\n )}\n </button>\n )\n }\n\n if (!isLocked && onDownload && source) {\n return (\n <a\n href={source}\n onClick={onDownload}\n className=\"mt-3 inline-flex h-10 w-full items-center justify-center gap-2 rounded-full bg-[#121110] px-4 text-sm font-medium leading-none !text-white hover:bg-[#2a2928]\"\n >\n <DownloadSimpleIcon className=\"size-4\" weight=\"bold\" />\n Download\n </a>\n )\n }\n\n return null\n}\n\n\nconst VisitorCard: React.FC<VisitorCardProps> = (props) => {\n const {\n title,\n amountText,\n thumbnail,\n source: sourceProp,\n mimeType = 'application/octet-stream',\n detail,\n onUnlock,\n onDownload,\n paymentStatus,\n } = props\n const [source, setSource] = useState(sourceProp)\n const [unlockLoading, setUnlockLoading] = useState(false)\n\n useEffect(() => {\n if (sourceProp !== undefined) setSource(sourceProp)\n }, [sourceProp])\n\n const isLocked = source === undefined\n const sourceType = getSourceType(mimeType)\n\n const handleUnlock = async () => {\n if (!onUnlock) return\n setUnlockLoading(true)\n try {\n const result = await onUnlock()\n setSource(result.source)\n } catch (err) {\n if (isDevBuild()) console.debug('[LockedAttachment] onUnlock failed', err)\n } finally {\n setUnlockLoading(false)\n }\n }\n\n let mediaPreview: React.ReactNode\n if (sourceType === 'image') {\n mediaPreview = (\n <ImagePreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n title={title}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n } else if (sourceType === 'document') {\n mediaPreview = (\n <DocumentPreview\n thumbnail={thumbnail}\n mimeType={mimeType}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n } else {\n mediaPreview = (\n <MediaPreview\n source={source}\n thumbnail={thumbnail}\n mimeType={mimeType}\n paymentStatus={paymentStatus}\n isLocked={isLocked}\n />\n )\n }\n\n return (\n <div className=\"w-[280px] select-none overflow-hidden rounded-[24px] bg-white shadow-card\">\n {mediaPreview}\n <div className=\"px-4 pb-3 pt-3\">\n <p className=\"mb-1.5 truncate text-base font-medium text-black\">\n {title}\n </p>\n <div className=\"flex items-center gap-1\">\n {renderTypeIcon(mimeType, {\n className: 'size-5 shrink-0 text-black/55',\n weight: 'regular',\n })}\n {detail && (\n <span className=\"text-xs font-medium text-black/55\">{detail}</span>\n )}\n {paymentStatus === 'paid' ? (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-[#008236]\">\n Purchased\n </span>\n <CheckCircleIcon\n className=\"size-4 text-[#008236]\"\n weight=\"bold\"\n />\n </>\n ) : (\n amountText && (\n <>\n <span className=\"text-xs font-medium text-black/55\">•</span>\n <span className=\"text-xs font-medium text-black/55\">\n {amountText}\n </span>\n </>\n )\n )}\n </div>\n <CardActions\n isLocked={isLocked}\n unlockLoading={unlockLoading}\n source={source}\n onUnlock={onUnlock ? handleUnlock : undefined}\n onDownload={onDownload}\n />\n </div>\n </div>\n )\n}\n\nexport default VisitorCard\n"],"names":["getLockIcon","paymentStatus","LockOpenIcon","LockSimpleIcon","LockOverlay","props","Icon","jsx","LockedPreview","thumbnail","mimeType","LockIcon","jsxs","ImagePreview","source","title","isLocked","sourceReady","setSourceReady","useState","useEffect","DocumentPreview","MediaPreview","MediaPlayer","LoadingDots","CardActions","unlockLoading","onUnlock","onDownload","Fragment","DownloadSimpleIcon","VisitorCard","amountText","sourceProp","detail","setSource","setUnlockLoading","sourceType","getSourceType","handleUnlock","result","mediaPreview","renderTypeIcon","CheckCircleIcon"],"mappings":"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"}
|