@linktr.ee/messaging-react 1.26.1 → 1.27.0
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-B6M8dB0U.js +87 -0
- package/dist/Creator-B6M8dB0U.js.map +1 -0
- package/dist/MediaPlayer-DsjlYGGH.js +539 -0
- package/dist/MediaPlayer-DsjlYGGH.js.map +1 -0
- package/dist/Preview-DqAv16NS.js +87 -0
- package/dist/Preview-DqAv16NS.js.map +1 -0
- package/dist/Visitor-CpmFZRGO.js +175 -0
- package/dist/Visitor-CpmFZRGO.js.map +1 -0
- package/dist/dash.all.min-Duv4lvGS.js +18858 -0
- package/dist/dash.all.min-Duv4lvGS.js.map +1 -0
- package/dist/hls-Bogc7CBn.js +21710 -0
- package/dist/hls-Bogc7CBn.js.map +1 -0
- package/dist/index-Da-xN4Yq.js +16142 -0
- package/dist/index-Da-xN4Yq.js.map +1 -0
- package/dist/index-Dj9rqWcU.js +69 -0
- package/dist/index-Dj9rqWcU.js.map +1 -0
- package/dist/index.d.ts +73 -10
- package/dist/index.js +979 -934
- package/dist/index.js.map +1 -1
- package/dist/mixin-B6jYfIcp.js +808 -0
- package/dist/mixin-B6jYfIcp.js.map +1 -0
- package/dist/react-BxlQMOfz.js +419 -0
- package/dist/react-BxlQMOfz.js.map +1 -0
- package/dist/react-COAP-MIW.js +377 -0
- package/dist/react-COAP-MIW.js.map +1 -0
- package/dist/react-Cn4WlMcl.js +3108 -0
- package/dist/react-Cn4WlMcl.js.map +1 -0
- package/dist/react-CwTJArKY.js +459 -0
- package/dist/react-CwTJArKY.js.map +1 -0
- package/dist/react-DkfS_atT.js +373 -0
- package/dist/react-DkfS_atT.js.map +1 -0
- package/dist/react-Pea5fum1.js +286 -0
- package/dist/react-Pea5fum1.js.map +1 -0
- package/dist/react-RiBbsUDd.js +534 -0
- package/dist/react-RiBbsUDd.js.map +1 -0
- package/dist/react-dS1WBxxz.js +238 -0
- package/dist/react-dS1WBxxz.js.map +1 -0
- package/package.json +2 -1
- package/src/components/ChannelView.tsx +12 -2
- package/src/components/CustomMessage/CustomMessage.stories.tsx +173 -41
- package/src/components/CustomMessage/MessageTag.tsx +5 -0
- package/src/components/CustomMessage/index.tsx +43 -4
- package/src/components/LockedAttachment/LockedAttachment.stories.tsx +249 -0
- package/src/components/LockedAttachment/components/Creator.tsx +171 -0
- package/src/components/LockedAttachment/components/MediaPlayer.tsx +299 -0
- package/src/components/LockedAttachment/components/Visitor.tsx +293 -0
- package/src/components/LockedAttachment/index.tsx +39 -0
- package/src/components/LockedAttachment/types.ts +18 -0
- package/src/components/LockedAttachment/utils/icons.ts +52 -0
- package/src/components/LockedAttachment/utils/mimeType.test.ts +97 -0
- package/src/components/LockedAttachment/utils/mimeType.ts +35 -0
- package/src/components/ParticipantPicker/index.tsx +8 -1
- package/src/hooks/useParticipants.ts +3 -2
- package/src/index.ts +4 -0
- package/src/stories/decorators/storyUser.tsx +37 -0
- package/src/stream-custom-data.ts +9 -3
- package/src/types.ts +21 -1
- package/src/utils/isDevBuild.ts +10 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { Meta, StoryFn } from '@storybook/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import LockedAttachment, { type VisitorCardProps } from '.'
|
|
5
|
+
|
|
6
|
+
const VIDEO_THUMBNAIL = '/video-thumbnail.jpg'
|
|
7
|
+
const VIDEO_THUMBNAIL_BLURRED = '/video-thumbnail-blurred.jpg'
|
|
8
|
+
const VIDEO_SOURCE = '/video-source.mp4'
|
|
9
|
+
|
|
10
|
+
const IMAGE_THUMBNAIL = '/image-thumbnail.jpg'
|
|
11
|
+
const IMAGE_THUMBNAIL_BLURRED = '/image-thumbnail-blurred.jpg'
|
|
12
|
+
const IMAGE_SOURCE = '/image-source.jpg'
|
|
13
|
+
|
|
14
|
+
const DOCUMENT_THUMBNAIL = '/document-thumbnail.jpg'
|
|
15
|
+
const DOCUMENT_THUMBNAIL_BLURRED = '/document-thumbnail-blurred.jpg'
|
|
16
|
+
const DOCUMENT_SOURCE = '/document-source.pdf'
|
|
17
|
+
|
|
18
|
+
const AUDIO_THUMBNAIL = '/audio-thumbnail.jpg'
|
|
19
|
+
const AUDIO_THUMBNAIL_BLURRED = '/audio-thumbnail-blurred.jpg'
|
|
20
|
+
const AUDIO_SOURCE = '/audio-source.mp3'
|
|
21
|
+
|
|
22
|
+
const meta: Meta = {
|
|
23
|
+
title: 'Components/LockedAttachment',
|
|
24
|
+
component: LockedAttachment,
|
|
25
|
+
parameters: { layout: 'centered' },
|
|
26
|
+
}
|
|
27
|
+
export default meta
|
|
28
|
+
|
|
29
|
+
type InteractiveProps = Omit<VisitorCardProps, 'onUnlock' | 'onDownload'> & {
|
|
30
|
+
unlockedSource: string
|
|
31
|
+
unlockedPoster?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Interactive = ({ unlockedSource, unlockedPoster, ...props }: InteractiveProps) => (
|
|
35
|
+
<LockedAttachment
|
|
36
|
+
{...props}
|
|
37
|
+
onUnlock={async () => {
|
|
38
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
39
|
+
const res = await fetch(unlockedSource)
|
|
40
|
+
const blob = await res.blob()
|
|
41
|
+
return { source: URL.createObjectURL(blob), poster: unlockedPoster }
|
|
42
|
+
}}
|
|
43
|
+
onDownload={() => {}}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const VARIANTS = [
|
|
48
|
+
{ label: 'Video', title: "Alicia's Workout Plan", mimeType: 'video/mp4', detail: '1:20', poster: VIDEO_THUMBNAIL, thumbnail: VIDEO_THUMBNAIL_BLURRED, source: VIDEO_SOURCE },
|
|
49
|
+
{ label: 'Audio', title: 'Morning Meditation', mimeType: 'audio/mpeg', detail: '4:35', poster: AUDIO_THUMBNAIL, thumbnail: AUDIO_THUMBNAIL_BLURRED, source: AUDIO_SOURCE },
|
|
50
|
+
{ label: 'Image', title: 'Picture of my cat', mimeType: 'image/jpeg', detail: '3.2 MB', poster: IMAGE_THUMBNAIL, thumbnail: IMAGE_THUMBNAIL_BLURRED, source: IMAGE_SOURCE },
|
|
51
|
+
{ label: 'Document', title: 'Strength Training Guide', mimeType: 'application/zip', detail: '14 files', poster: DOCUMENT_THUMBNAIL, thumbnail: DOCUMENT_THUMBNAIL_BLURRED, source: DOCUMENT_SOURCE },
|
|
52
|
+
{ label: 'Unknown', title: 'Unknown Attachment', mimeType: 'application/octet-stream', detail: undefined, poster: undefined, thumbnail: undefined, source: DOCUMENT_SOURCE },
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
const NO_POSTER_VARIANTS = [
|
|
56
|
+
{ label: 'Video', title: "Alicia's Workout Plan", mimeType: 'video/mp4', detail: '1:20', source: VIDEO_SOURCE },
|
|
57
|
+
{ label: 'Audio', title: 'Morning Meditation', mimeType: 'audio/mpeg', detail: '4:35', source: AUDIO_SOURCE },
|
|
58
|
+
{ label: 'Image', title: 'Picture of my cat', mimeType: 'image/jpeg', detail: '3.2 MB', source: IMAGE_SOURCE },
|
|
59
|
+
{ label: 'Document', title: 'Strength Training Guide', mimeType: 'application/zip', detail: '14 files', source: DOCUMENT_SOURCE },
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
const Table = ({ children }: { children: React.ReactNode }) => (
|
|
63
|
+
<div className="p-12">
|
|
64
|
+
<table className="border-separate border-spacing-4">
|
|
65
|
+
{children}
|
|
66
|
+
</table>
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const TableHead = ({ variants }: { variants: { label: string; mimeType: string }[] }) => (
|
|
71
|
+
<thead>
|
|
72
|
+
<tr>
|
|
73
|
+
<th className="text-left text-xs font-medium text-black/40 pb-2" />
|
|
74
|
+
{variants.map(({ label, mimeType }) => (
|
|
75
|
+
<th key={mimeType} className="text-left text-xs font-medium text-black/40 pb-2">{label}</th>
|
|
76
|
+
))}
|
|
77
|
+
</tr>
|
|
78
|
+
</thead>
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
export const Visitor: StoryFn = () => (
|
|
82
|
+
<Table>
|
|
83
|
+
<TableHead variants={VARIANTS} />
|
|
84
|
+
<tbody>
|
|
85
|
+
<tr>
|
|
86
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Locked</td>
|
|
87
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnail, poster, source }) => (
|
|
88
|
+
<td key={mimeType} className="align-top">
|
|
89
|
+
<Interactive
|
|
90
|
+
title={title}
|
|
91
|
+
amountText="AU$9.99"
|
|
92
|
+
thumbnail={thumbnail}
|
|
93
|
+
poster={poster}
|
|
94
|
+
mimeType={mimeType}
|
|
95
|
+
detail={detail}
|
|
96
|
+
unlockedSource={source}
|
|
97
|
+
/>
|
|
98
|
+
</td>
|
|
99
|
+
))}
|
|
100
|
+
</tr>
|
|
101
|
+
<tr>
|
|
102
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Purchased</td>
|
|
103
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnail, poster, source }) => (
|
|
104
|
+
<td key={mimeType} className="align-top">
|
|
105
|
+
<Interactive
|
|
106
|
+
title={title}
|
|
107
|
+
amountText="AU$9.99"
|
|
108
|
+
thumbnail={thumbnail}
|
|
109
|
+
unlockedPoster={poster}
|
|
110
|
+
mimeType={mimeType}
|
|
111
|
+
detail={detail}
|
|
112
|
+
unlockedSource={source}
|
|
113
|
+
paymentStatus="paid"
|
|
114
|
+
/>
|
|
115
|
+
</td>
|
|
116
|
+
))}
|
|
117
|
+
</tr>
|
|
118
|
+
<tr>
|
|
119
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Unlocked</td>
|
|
120
|
+
{VARIANTS.map(({ title, mimeType, detail, poster, source }) => (
|
|
121
|
+
<td key={mimeType} className="align-top">
|
|
122
|
+
<LockedAttachment
|
|
123
|
+
title={title}
|
|
124
|
+
poster={poster}
|
|
125
|
+
source={source}
|
|
126
|
+
mimeType={mimeType}
|
|
127
|
+
detail={detail}
|
|
128
|
+
amountText="AU$9.99"
|
|
129
|
+
paymentStatus="paid"
|
|
130
|
+
onDownload={() => {}}
|
|
131
|
+
/>
|
|
132
|
+
</td>
|
|
133
|
+
))}
|
|
134
|
+
</tr>
|
|
135
|
+
</tbody>
|
|
136
|
+
</Table>
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
export const Creator: StoryFn = () => (
|
|
140
|
+
<Table>
|
|
141
|
+
<TableHead variants={VARIANTS} />
|
|
142
|
+
<tbody>
|
|
143
|
+
<tr>
|
|
144
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Preview</td>
|
|
145
|
+
{VARIANTS.map(({ mimeType, detail, thumbnail, poster, source }) => (
|
|
146
|
+
<td key={mimeType} className="align-top">
|
|
147
|
+
<LockedAttachment
|
|
148
|
+
isCreator
|
|
149
|
+
thumbnail={thumbnail}
|
|
150
|
+
poster={poster}
|
|
151
|
+
source={source}
|
|
152
|
+
mimeType={mimeType}
|
|
153
|
+
detail={detail}
|
|
154
|
+
placeholderAmountText="A$0.00"
|
|
155
|
+
/>
|
|
156
|
+
</td>
|
|
157
|
+
))}
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Sent</td>
|
|
161
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnail, poster, source }) => (
|
|
162
|
+
<td key={mimeType} className="align-top">
|
|
163
|
+
<LockedAttachment
|
|
164
|
+
isCreator
|
|
165
|
+
title={title}
|
|
166
|
+
thumbnail={thumbnail}
|
|
167
|
+
poster={poster}
|
|
168
|
+
source={source}
|
|
169
|
+
mimeType={mimeType}
|
|
170
|
+
detail={detail}
|
|
171
|
+
amountText="AU$9.99"
|
|
172
|
+
/>
|
|
173
|
+
</td>
|
|
174
|
+
))}
|
|
175
|
+
</tr>
|
|
176
|
+
<tr>
|
|
177
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Sold</td>
|
|
178
|
+
{VARIANTS.map(({ title, mimeType, detail, thumbnail, poster, source }) => (
|
|
179
|
+
<td key={mimeType} className="align-top">
|
|
180
|
+
<LockedAttachment
|
|
181
|
+
isCreator
|
|
182
|
+
title={title}
|
|
183
|
+
thumbnail={thumbnail}
|
|
184
|
+
poster={poster}
|
|
185
|
+
source={source}
|
|
186
|
+
mimeType={mimeType}
|
|
187
|
+
detail={detail}
|
|
188
|
+
amountText="AU$9.99"
|
|
189
|
+
paymentStatus="paid"
|
|
190
|
+
/>
|
|
191
|
+
</td>
|
|
192
|
+
))}
|
|
193
|
+
</tr>
|
|
194
|
+
</tbody>
|
|
195
|
+
</Table>
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
export const NoPoster: StoryFn = () => (
|
|
199
|
+
<Table>
|
|
200
|
+
<TableHead variants={NO_POSTER_VARIANTS} />
|
|
201
|
+
<tbody>
|
|
202
|
+
<tr>
|
|
203
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Creator</td>
|
|
204
|
+
{NO_POSTER_VARIANTS.map(({ title, mimeType, detail, source }) => (
|
|
205
|
+
<td key={mimeType} className="align-top">
|
|
206
|
+
<LockedAttachment
|
|
207
|
+
isCreator
|
|
208
|
+
title={title}
|
|
209
|
+
source={source}
|
|
210
|
+
mimeType={mimeType}
|
|
211
|
+
detail={detail}
|
|
212
|
+
amountText="AU$9.99"
|
|
213
|
+
/>
|
|
214
|
+
</td>
|
|
215
|
+
))}
|
|
216
|
+
</tr>
|
|
217
|
+
<tr>
|
|
218
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Locked</td>
|
|
219
|
+
{NO_POSTER_VARIANTS.map(({ title, mimeType, detail, source }) => (
|
|
220
|
+
<td key={mimeType} className="align-top">
|
|
221
|
+
<Interactive
|
|
222
|
+
title={title}
|
|
223
|
+
amountText="AU$9.99"
|
|
224
|
+
mimeType={mimeType}
|
|
225
|
+
detail={detail}
|
|
226
|
+
unlockedSource={source}
|
|
227
|
+
/>
|
|
228
|
+
</td>
|
|
229
|
+
))}
|
|
230
|
+
</tr>
|
|
231
|
+
<tr>
|
|
232
|
+
<td className="text-xs font-medium text-black/40 pr-4 align-top pt-2">Unlocked</td>
|
|
233
|
+
{NO_POSTER_VARIANTS.map(({ title, mimeType, detail, source }) => (
|
|
234
|
+
<td key={mimeType} className="align-top">
|
|
235
|
+
<LockedAttachment
|
|
236
|
+
title={title}
|
|
237
|
+
source={source}
|
|
238
|
+
mimeType={mimeType}
|
|
239
|
+
detail={detail}
|
|
240
|
+
amountText="AU$9.99"
|
|
241
|
+
paymentStatus="paid"
|
|
242
|
+
onDownload={() => {}}
|
|
243
|
+
/>
|
|
244
|
+
</td>
|
|
245
|
+
))}
|
|
246
|
+
</tr>
|
|
247
|
+
</tbody>
|
|
248
|
+
</Table>
|
|
249
|
+
)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { CheckCircleIcon, EyeIcon, EyeSlashIcon } from '@phosphor-icons/react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
|
+
|
|
5
|
+
import type { LockedAttachmentBaseProps, PaymentStatus } from '../types'
|
|
6
|
+
import { renderTypeIcon } from '../utils/icons'
|
|
7
|
+
import { getSourceType, type AttachmentSourceType } from '../utils/mimeType'
|
|
8
|
+
|
|
9
|
+
import MediaPlayer from './MediaPlayer'
|
|
10
|
+
|
|
11
|
+
export interface CreatorCardProps extends LockedAttachmentBaseProps {
|
|
12
|
+
title?: string
|
|
13
|
+
placeholderTitle?: string
|
|
14
|
+
placeholderAmountText?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const CloseButton = ({ onClose }: { onClose: () => void }) => (
|
|
18
|
+
<button
|
|
19
|
+
type="button"
|
|
20
|
+
onClick={onClose}
|
|
21
|
+
className="absolute right-3 top-3 z-40 flex size-8 items-center justify-center rounded-full bg-black/60 text-white"
|
|
22
|
+
aria-label="Close preview"
|
|
23
|
+
>
|
|
24
|
+
<EyeIcon className="size-4" weight="fill" />
|
|
25
|
+
</button>
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
interface CollapsedThumbnailProps {
|
|
29
|
+
thumbnail?: string
|
|
30
|
+
mimeType: string
|
|
31
|
+
canExpand: boolean
|
|
32
|
+
onExpand: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const CollapsedThumbnail: React.FC<CollapsedThumbnailProps> = ({ thumbnail, mimeType, canExpand, onExpand }) => {
|
|
36
|
+
return (
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
disabled={!canExpand}
|
|
40
|
+
className={classNames('relative aspect-video block w-full overflow-hidden border-0 bg-black/5 p-0 text-left appearance-none', { 'cursor-pointer': canExpand, 'cursor-default': !canExpand })}
|
|
41
|
+
onClick={onExpand}
|
|
42
|
+
aria-label={canExpand ? 'Expand attachment preview' : undefined}
|
|
43
|
+
>
|
|
44
|
+
{thumbnail
|
|
45
|
+
? <img src={thumbnail} alt="" className="absolute inset-0 h-full w-full object-cover" />
|
|
46
|
+
: <div className="absolute inset-0 flex items-center justify-center">{renderTypeIcon(mimeType, { className: 'size-12 text-black/20', weight: 'regular' })}</div>
|
|
47
|
+
}
|
|
48
|
+
{canExpand && (
|
|
49
|
+
<div className="pointer-events-none absolute right-3 top-3 flex size-8 items-center justify-center rounded-full bg-black/60 text-white">
|
|
50
|
+
<EyeSlashIcon className="size-4" weight="fill" />
|
|
51
|
+
</div>
|
|
52
|
+
)}
|
|
53
|
+
</button>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface ExpandedMediaProps {
|
|
58
|
+
source: string
|
|
59
|
+
mimeType: string
|
|
60
|
+
sourceType: AttachmentSourceType
|
|
61
|
+
poster?: string
|
|
62
|
+
thumbnail?: string
|
|
63
|
+
title?: string
|
|
64
|
+
onCollapse: () => void
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const getExpandedImgSrc = (sourceType: AttachmentSourceType, source: string, poster?: string, thumbnail?: string) =>
|
|
68
|
+
sourceType === 'document' ? (poster ?? thumbnail) : source
|
|
69
|
+
|
|
70
|
+
const ExpandedMedia: React.FC<ExpandedMediaProps> = ({ source, mimeType, sourceType, poster, thumbnail, title, onCollapse }) => {
|
|
71
|
+
if (sourceType === 'video' || sourceType === 'audio') {
|
|
72
|
+
return (
|
|
73
|
+
<div className="relative">
|
|
74
|
+
<MediaPlayer
|
|
75
|
+
source={source}
|
|
76
|
+
mimeType={mimeType}
|
|
77
|
+
poster={poster ?? thumbnail}
|
|
78
|
+
autoPlay
|
|
79
|
+
loop
|
|
80
|
+
controls={false}
|
|
81
|
+
showProgress
|
|
82
|
+
onContainerClick={onCollapse}
|
|
83
|
+
muted={sourceType === 'video'}
|
|
84
|
+
/>
|
|
85
|
+
<CloseButton onClose={onCollapse} />
|
|
86
|
+
</div>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
const imgSrc = getExpandedImgSrc(sourceType, source, poster, thumbnail)
|
|
90
|
+
return (
|
|
91
|
+
<div className="relative">
|
|
92
|
+
<button type="button" className="block w-full cursor-pointer border-0 p-0 text-left appearance-none" onClick={onCollapse} aria-label="Close preview">
|
|
93
|
+
<img src={imgSrc} alt={title ?? ''} className="block w-full" />
|
|
94
|
+
</button>
|
|
95
|
+
<CloseButton onClose={onCollapse} />
|
|
96
|
+
</div>
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface CreatorCardMetaProps {
|
|
101
|
+
title?: string
|
|
102
|
+
placeholderTitle: string
|
|
103
|
+
mimeType: string
|
|
104
|
+
detail?: string
|
|
105
|
+
paymentStatus?: PaymentStatus
|
|
106
|
+
displayAmountText?: string
|
|
107
|
+
isPlaceholderAmount: boolean
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const CreatorCardMeta: React.FC<CreatorCardMetaProps> = ({ title, placeholderTitle, mimeType, detail, paymentStatus, displayAmountText, isPlaceholderAmount }) => {
|
|
111
|
+
return (
|
|
112
|
+
<div className="px-4 pb-3 pt-3">
|
|
113
|
+
<p className={classNames('mb-1.5 truncate text-base font-medium', { 'text-black/30': !title, 'text-black': !!title })}>
|
|
114
|
+
{title || placeholderTitle}
|
|
115
|
+
</p>
|
|
116
|
+
<div className="flex items-center gap-1">
|
|
117
|
+
{renderTypeIcon(mimeType, { className: 'size-5 shrink-0 text-black/55', weight: 'regular' })}
|
|
118
|
+
{detail && <span className="text-xs font-medium text-black/55">{detail}</span>}
|
|
119
|
+
{paymentStatus === 'paid' ? (
|
|
120
|
+
<>
|
|
121
|
+
<span className="text-xs font-medium text-black/55">•</span>
|
|
122
|
+
<span className="text-xs font-medium text-[#008236]">Purchased</span>
|
|
123
|
+
<CheckCircleIcon className="size-4 text-[#008236]" weight="bold" />
|
|
124
|
+
</>
|
|
125
|
+
) : displayAmountText && (
|
|
126
|
+
<>
|
|
127
|
+
<span className={classNames('text-xs font-medium', { 'text-black/30': isPlaceholderAmount, 'text-black/55': !isPlaceholderAmount })}>•</span>
|
|
128
|
+
<span className={classNames('text-xs font-medium', { 'text-black/30': isPlaceholderAmount, 'text-black/55': !isPlaceholderAmount })}>{displayAmountText}</span>
|
|
129
|
+
</>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const CreatorCard: React.FC<CreatorCardProps> = ({
|
|
137
|
+
title,
|
|
138
|
+
mimeType = 'application/octet-stream',
|
|
139
|
+
thumbnail,
|
|
140
|
+
poster,
|
|
141
|
+
source,
|
|
142
|
+
detail,
|
|
143
|
+
amountText,
|
|
144
|
+
placeholderTitle = 'Attachment title',
|
|
145
|
+
placeholderAmountText,
|
|
146
|
+
paymentStatus,
|
|
147
|
+
}) => {
|
|
148
|
+
const sourceType = getSourceType(mimeType)
|
|
149
|
+
const [expanded, setExpanded] = useState(false)
|
|
150
|
+
|
|
151
|
+
const displayAmountText = placeholderAmountText ?? amountText
|
|
152
|
+
const isPlaceholderAmount = !!placeholderAmountText
|
|
153
|
+
const canExpand = sourceType === 'document'
|
|
154
|
+
? !!(source && (poster || thumbnail))
|
|
155
|
+
: !!source
|
|
156
|
+
|
|
157
|
+
const collapse = () => setExpanded(false)
|
|
158
|
+
|
|
159
|
+
const mediaPreview = expanded && source
|
|
160
|
+
? <ExpandedMedia source={source} mimeType={mimeType} sourceType={sourceType} poster={poster} thumbnail={thumbnail} title={title} onCollapse={collapse} />
|
|
161
|
+
: <CollapsedThumbnail thumbnail={thumbnail} mimeType={mimeType} canExpand={canExpand} onExpand={() => setExpanded(true)} />
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="w-[280px] overflow-hidden rounded-3xl bg-white shadow-[0px_0px_0px_1px_rgba(0,0,0,0.04),0px_1px_2px_0px_rgba(0,0,0,0.04),0px_8px_32px_0px_rgba(0,0,0,0.1)]">
|
|
165
|
+
{mediaPreview}
|
|
166
|
+
<CreatorCardMeta title={title} placeholderTitle={placeholderTitle} mimeType={mimeType} detail={detail} paymentStatus={paymentStatus} displayAmountText={displayAmountText} isPlaceholderAmount={isPlaceholderAmount} />
|
|
167
|
+
</div>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default CreatorCard
|