sanity-plugin-mux-input 3.0.5 → 4.0.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/index.js +28 -28
- package/dist/index.js.map +1 -1
- package/package.json +5 -15
- package/dist/index.cjs +0 -5746
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -288
- package/dist/index.d.cts.map +0 -1
- package/sanity.json +0 -8
- package/src/_exports/index.ts +0 -73
- package/src/actions/assets.ts +0 -152
- package/src/actions/secrets.ts +0 -110
- package/src/actions/upload.ts +0 -308
- package/src/clients/upChunkObservable.ts +0 -54
- package/src/components/AddCaptionDialog.tsx +0 -440
- package/src/components/CaptionsDialog.tsx +0 -23
- package/src/components/ConfigureApi.styled.tsx +0 -19
- package/src/components/ConfigureApi.tsx +0 -296
- package/src/components/DraggableWatermark.tsx +0 -885
- package/src/components/EditCaptionDialog.tsx +0 -511
- package/src/components/EditThumbnailDialog.tsx +0 -121
- package/src/components/ErrorBoundaryCard.tsx +0 -97
- package/src/components/FileInputButton.tsx +0 -54
- package/src/components/FileInputMenuItem.styled.tsx +0 -36
- package/src/components/FileInputMenuItem.tsx +0 -85
- package/src/components/FormField.tsx +0 -38
- package/src/components/IconInfo.tsx +0 -22
- package/src/components/ImportVideosFromMux.tsx +0 -339
- package/src/components/Input.styled.tsx +0 -22
- package/src/components/Input.tsx +0 -78
- package/src/components/InputBrowser.tsx +0 -41
- package/src/components/MuxLogo.tsx +0 -42
- package/src/components/Onboard.tsx +0 -65
- package/src/components/PageSelector.tsx +0 -54
- package/src/components/Player.styled.tsx +0 -11
- package/src/components/Player.tsx +0 -117
- package/src/components/PlayerActionsMenu.tsx +0 -191
- package/src/components/ResyncMetadata.tsx +0 -278
- package/src/components/SelectAsset.tsx +0 -39
- package/src/components/SelectSortOptions.tsx +0 -45
- package/src/components/SpinnerBox.tsx +0 -16
- package/src/components/StudioTool.tsx +0 -24
- package/src/components/TextTracksEditor.tsx +0 -117
- package/src/components/TextTracksManager.tsx +0 -738
- package/src/components/UploadConfiguration.tsx +0 -696
- package/src/components/UploadPlaceholder.tsx +0 -88
- package/src/components/UploadProgress.tsx +0 -80
- package/src/components/Uploader.styled.tsx +0 -65
- package/src/components/Uploader.tsx +0 -499
- package/src/components/VideoDetails/DeleteDialog.tsx +0 -148
- package/src/components/VideoDetails/VideoDetails.tsx +0 -358
- package/src/components/VideoDetails/VideoReferences.tsx +0 -63
- package/src/components/VideoDetails/useVideoDetails.ts +0 -103
- package/src/components/VideoInBrowser.tsx +0 -245
- package/src/components/VideoMetadata.tsx +0 -45
- package/src/components/VideoPlayer.tsx +0 -241
- package/src/components/VideoThumbnail.tsx +0 -139
- package/src/components/VideosBrowser.tsx +0 -100
- package/src/components/documentPreview/DocumentPreview.tsx +0 -84
- package/src/components/documentPreview/DraftStatus.tsx +0 -34
- package/src/components/documentPreview/MissingSchemaType.tsx +0 -32
- package/src/components/documentPreview/PaneItemPreview.tsx +0 -67
- package/src/components/documentPreview/PublishedStatus.tsx +0 -35
- package/src/components/documentPreview/TimeAgo.tsx +0 -12
- package/src/components/icons/Audio.tsx +0 -13
- package/src/components/icons/Resolution.tsx +0 -12
- package/src/components/icons/StopWatch.tsx +0 -20
- package/src/components/icons/ToolIcon.tsx +0 -19
- package/src/components/uploadConfiguration/PlaybackPolicy.tsx +0 -133
- package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +0 -76
- package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +0 -29
- package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +0 -72
- package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +0 -180
- package/src/components/withFocusRing/helpers.ts +0 -24
- package/src/components/withFocusRing/index.ts +0 -1
- package/src/components/withFocusRing/withFocusRing.ts +0 -30
- package/src/context/DialogStateContext.tsx +0 -33
- package/src/context/DrmPlaybackWarningContext.tsx +0 -97
- package/src/hooks/useAccessControl.ts +0 -13
- package/src/hooks/useAssetDocumentValues.ts +0 -11
- package/src/hooks/useAssets.ts +0 -73
- package/src/hooks/useCancelUpload.ts +0 -22
- package/src/hooks/useClient.ts +0 -8
- package/src/hooks/useDialogState.ts +0 -11
- package/src/hooks/useDocReferences.ts +0 -21
- package/src/hooks/useFetchFileSize.ts +0 -55
- package/src/hooks/useImportMuxAssets.ts +0 -132
- package/src/hooks/useInView.ts +0 -41
- package/src/hooks/useMediaMetadata.ts +0 -104
- package/src/hooks/useMuxAssets.ts +0 -179
- package/src/hooks/useMuxPolling.ts +0 -52
- package/src/hooks/useResyncAsset.ts +0 -110
- package/src/hooks/useResyncMuxMetadata.ts +0 -169
- package/src/hooks/useSaveSecrets.ts +0 -78
- package/src/hooks/useSecretsDocumentValues.ts +0 -38
- package/src/hooks/useSecretsFormState.ts +0 -47
- package/src/plugin.tsx +0 -31
- package/src/sanity-ui.d.ts +0 -5
- package/src/schema.ts +0 -196
- package/src/util/addKeysToMuxData.ts +0 -30
- package/src/util/asserters.ts +0 -23
- package/src/util/assetTitlePlaceholder.ts +0 -31
- package/src/util/constants.ts +0 -15
- package/src/util/convertWatermarkToMux.ts +0 -160
- package/src/util/createSearchFilter.ts +0 -76
- package/src/util/createUrlParamsObject.ts +0 -29
- package/src/util/extractFiles.ts +0 -67
- package/src/util/formatBytes.ts +0 -31
- package/src/util/formatDriveShareLink.ts +0 -64
- package/src/util/formatSeconds.ts +0 -48
- package/src/util/generateJwt.ts +0 -57
- package/src/util/getAnimatedPosterSrc.ts +0 -26
- package/src/util/getPlaybackPolicy.ts +0 -69
- package/src/util/getPosterSrc.ts +0 -28
- package/src/util/getVideoMetadata.ts +0 -23
- package/src/util/getVideoSrc.ts +0 -23
- package/src/util/parsers.ts +0 -5
- package/src/util/pluginVersion.ts +0 -5
- package/src/util/readSecrets.ts +0 -38
- package/src/util/roundPxString.ts +0 -16
- package/src/util/textTracks.ts +0 -222
- package/src/util/tryWithSuspend.ts +0 -22
- package/src/util/types.ts +0 -566
- package/v2-incompatible.js +0 -11
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import {CheckmarkCircleIcon, ErrorOutlineIcon, SyncIcon} from '@sanity/icons'
|
|
2
|
-
import {Box, Button, Card, Dialog, Flex, Heading, Radio, Spinner, Stack, Text} from '@sanity/ui'
|
|
3
|
-
import {useState} from 'react'
|
|
4
|
-
|
|
5
|
-
import useResyncMuxMetadata from '../hooks/useResyncMuxMetadata'
|
|
6
|
-
import {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'
|
|
7
|
-
import {DIALOGS_Z_INDEX} from '../util/constants'
|
|
8
|
-
|
|
9
|
-
type SyncOption = 'fillEmpty' | 'syncTitles' | 'fullResync'
|
|
10
|
-
|
|
11
|
-
interface OptionCardProps {
|
|
12
|
-
id: SyncOption
|
|
13
|
-
selected: boolean
|
|
14
|
-
onSelect: (id: SyncOption) => void
|
|
15
|
-
title: string
|
|
16
|
-
count: number
|
|
17
|
-
description: string
|
|
18
|
-
disabled?: boolean
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function OptionCard({
|
|
22
|
-
id,
|
|
23
|
-
selected,
|
|
24
|
-
onSelect,
|
|
25
|
-
title,
|
|
26
|
-
count,
|
|
27
|
-
description,
|
|
28
|
-
disabled,
|
|
29
|
-
}: OptionCardProps) {
|
|
30
|
-
return (
|
|
31
|
-
<Card
|
|
32
|
-
as="label"
|
|
33
|
-
padding={3}
|
|
34
|
-
radius={2}
|
|
35
|
-
border
|
|
36
|
-
tone={selected ? 'primary' : 'default'}
|
|
37
|
-
style={{
|
|
38
|
-
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
39
|
-
opacity: disabled ? 0.5 : 1,
|
|
40
|
-
}}
|
|
41
|
-
>
|
|
42
|
-
<Flex gap={3} align="flex-start">
|
|
43
|
-
<Box paddingTop={1}>
|
|
44
|
-
<Radio
|
|
45
|
-
checked={selected}
|
|
46
|
-
onChange={() => onSelect(id)}
|
|
47
|
-
disabled={disabled}
|
|
48
|
-
name="sync-option"
|
|
49
|
-
/>
|
|
50
|
-
</Box>
|
|
51
|
-
<Stack space={2} flex={1}>
|
|
52
|
-
<Flex align="center" gap={2}>
|
|
53
|
-
<Text size={2} weight="semibold">
|
|
54
|
-
{title} ({count})
|
|
55
|
-
</Text>
|
|
56
|
-
</Flex>
|
|
57
|
-
<Text size={1} muted>
|
|
58
|
-
{description}
|
|
59
|
-
</Text>
|
|
60
|
-
</Stack>
|
|
61
|
-
</Flex>
|
|
62
|
-
</Card>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function ResyncMetadataDialog(props: ReturnType<typeof useResyncMuxMetadata>) {
|
|
67
|
-
const {resyncState} = props
|
|
68
|
-
|
|
69
|
-
const videosToUpdate = props.matchedAssets?.filter((m) => m.muxAsset).length || 0
|
|
70
|
-
const videosWithEmptyOrPlaceholder =
|
|
71
|
-
props.matchedAssets?.filter(
|
|
72
|
-
(m) => m.muxAsset && m.muxTitle && isEmptyOrPlaceholderTitle(m.currentTitle, m.muxAsset.id),
|
|
73
|
-
).length || 0
|
|
74
|
-
|
|
75
|
-
const hasEmptyTitles = videosWithEmptyOrPlaceholder > 0
|
|
76
|
-
const defaultOption: SyncOption = hasEmptyTitles ? 'fillEmpty' : 'syncTitles'
|
|
77
|
-
const [selectedOption, setSelectedOption] = useState<SyncOption>(defaultOption)
|
|
78
|
-
|
|
79
|
-
const canTriggerResync = resyncState === 'idle' || resyncState === 'error'
|
|
80
|
-
const isResyncing = resyncState === 'syncing'
|
|
81
|
-
const isDone = resyncState === 'done'
|
|
82
|
-
const isLoading = props.muxAssets.loading || props.sanityAssetsLoading
|
|
83
|
-
|
|
84
|
-
const handleSync = () => {
|
|
85
|
-
switch (selectedOption) {
|
|
86
|
-
case 'fillEmpty':
|
|
87
|
-
void props.syncOnlyEmpty()
|
|
88
|
-
break
|
|
89
|
-
case 'syncTitles':
|
|
90
|
-
void props.syncAllVideos()
|
|
91
|
-
break
|
|
92
|
-
case 'fullResync':
|
|
93
|
-
void props.syncFullData()
|
|
94
|
-
break
|
|
95
|
-
default:
|
|
96
|
-
break
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<Dialog
|
|
102
|
-
animate
|
|
103
|
-
header="Sync with Mux"
|
|
104
|
-
zOffset={DIALOGS_Z_INDEX}
|
|
105
|
-
id="resync-metadata-dialog"
|
|
106
|
-
onClose={props.closeDialog}
|
|
107
|
-
onClickOutside={props.closeDialog}
|
|
108
|
-
width={1}
|
|
109
|
-
position="fixed"
|
|
110
|
-
footer={
|
|
111
|
-
!isDone && (
|
|
112
|
-
<Card padding={3}>
|
|
113
|
-
<Flex justify="flex-end" gap={2}>
|
|
114
|
-
<Button
|
|
115
|
-
fontSize={2}
|
|
116
|
-
padding={3}
|
|
117
|
-
mode="ghost"
|
|
118
|
-
text="Cancel"
|
|
119
|
-
onClick={props.closeDialog}
|
|
120
|
-
disabled={isResyncing}
|
|
121
|
-
/>
|
|
122
|
-
<Button
|
|
123
|
-
icon={SyncIcon}
|
|
124
|
-
fontSize={2}
|
|
125
|
-
padding={3}
|
|
126
|
-
text="Run sync"
|
|
127
|
-
tone="primary"
|
|
128
|
-
onClick={handleSync}
|
|
129
|
-
iconRight={isResyncing && Spinner}
|
|
130
|
-
disabled={!canTriggerResync || isLoading}
|
|
131
|
-
/>
|
|
132
|
-
</Flex>
|
|
133
|
-
</Card>
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
>
|
|
137
|
-
<Box padding={4}>
|
|
138
|
-
{/* LOADING ASSETS STATE */}
|
|
139
|
-
{isLoading && (
|
|
140
|
-
<Card tone="primary" marginBottom={4} padding={3} border radius={2}>
|
|
141
|
-
<Flex align="center" gap={4}>
|
|
142
|
-
<Spinner muted size={4} />
|
|
143
|
-
<Stack space={2}>
|
|
144
|
-
<Text size={2} weight="semibold">
|
|
145
|
-
Loading assets from Mux
|
|
146
|
-
</Text>
|
|
147
|
-
<Text size={1} muted>
|
|
148
|
-
This may take a while.
|
|
149
|
-
</Text>
|
|
150
|
-
</Stack>
|
|
151
|
-
</Flex>
|
|
152
|
-
</Card>
|
|
153
|
-
)}
|
|
154
|
-
|
|
155
|
-
{/* ERROR LOADING MUX */}
|
|
156
|
-
{props.muxAssets.error && (
|
|
157
|
-
<Card tone="critical" marginBottom={4} padding={3} border radius={2}>
|
|
158
|
-
<Flex align="center" gap={2}>
|
|
159
|
-
<ErrorOutlineIcon fontSize={36} />
|
|
160
|
-
<Stack space={2}>
|
|
161
|
-
<Text size={2} weight="semibold">
|
|
162
|
-
There was an error getting data from Mux
|
|
163
|
-
</Text>
|
|
164
|
-
<Text size={1}>Please try again or contact a developer for help.</Text>
|
|
165
|
-
</Stack>
|
|
166
|
-
</Flex>
|
|
167
|
-
</Card>
|
|
168
|
-
)}
|
|
169
|
-
|
|
170
|
-
{/* SYNCING STATE */}
|
|
171
|
-
{resyncState === 'syncing' && (
|
|
172
|
-
<Card tone="primary" marginBottom={4} padding={3} border radius={2}>
|
|
173
|
-
<Flex align="center" gap={4}>
|
|
174
|
-
<Spinner muted size={4} />
|
|
175
|
-
<Stack space={2}>
|
|
176
|
-
<Text size={2} weight="semibold">
|
|
177
|
-
Syncing metadata
|
|
178
|
-
</Text>
|
|
179
|
-
<Text size={1} muted>
|
|
180
|
-
Updating videos from Mux...
|
|
181
|
-
</Text>
|
|
182
|
-
</Stack>
|
|
183
|
-
</Flex>
|
|
184
|
-
</Card>
|
|
185
|
-
)}
|
|
186
|
-
|
|
187
|
-
{/* ERROR SYNCING */}
|
|
188
|
-
{resyncState === 'error' && (
|
|
189
|
-
<Card tone="critical" marginBottom={4} padding={3} border radius={2}>
|
|
190
|
-
<Flex align="center" gap={2}>
|
|
191
|
-
<ErrorOutlineIcon fontSize={36} />
|
|
192
|
-
<Stack space={2}>
|
|
193
|
-
<Text size={2} weight="semibold">
|
|
194
|
-
There was an error syncing metadata
|
|
195
|
-
</Text>
|
|
196
|
-
<Text size={1}>
|
|
197
|
-
{props.resyncError
|
|
198
|
-
? `Error: ${props.resyncError}`
|
|
199
|
-
: 'Please try again or contact a developer for help.'}
|
|
200
|
-
</Text>
|
|
201
|
-
</Stack>
|
|
202
|
-
</Flex>
|
|
203
|
-
</Card>
|
|
204
|
-
)}
|
|
205
|
-
|
|
206
|
-
{/* SUCCESS STATE */}
|
|
207
|
-
{resyncState === 'done' && (
|
|
208
|
-
<Stack paddingY={5} space={3} style={{textAlign: 'center'}}>
|
|
209
|
-
<Box>
|
|
210
|
-
<CheckmarkCircleIcon fontSize={48} />
|
|
211
|
-
</Box>
|
|
212
|
-
<Heading size={2}>Sync completed</Heading>
|
|
213
|
-
<Text size={2} muted>
|
|
214
|
-
Videos have been updated from Mux.
|
|
215
|
-
</Text>
|
|
216
|
-
</Stack>
|
|
217
|
-
)}
|
|
218
|
-
|
|
219
|
-
{/* OPTIONS */}
|
|
220
|
-
{!isDone && !isLoading && !props.muxAssets.error && (
|
|
221
|
-
<Stack space={4}>
|
|
222
|
-
<Text size={1} muted>
|
|
223
|
-
Found {videosToUpdate} video{videosToUpdate === 1 ? '' : 's'} linked to Mux.
|
|
224
|
-
</Text>
|
|
225
|
-
|
|
226
|
-
<Stack space={3}>
|
|
227
|
-
{hasEmptyTitles && (
|
|
228
|
-
<OptionCard
|
|
229
|
-
id="fillEmpty"
|
|
230
|
-
selected={selectedOption === 'fillEmpty'}
|
|
231
|
-
onSelect={setSelectedOption}
|
|
232
|
-
title="Fill missing titles only"
|
|
233
|
-
count={videosWithEmptyOrPlaceholder}
|
|
234
|
-
description="Updates only videos without a title or with placeholder titles (e.g., 'Asset #123') using the title from Mux."
|
|
235
|
-
disabled={isResyncing}
|
|
236
|
-
/>
|
|
237
|
-
)}
|
|
238
|
-
|
|
239
|
-
<OptionCard
|
|
240
|
-
id="syncTitles"
|
|
241
|
-
selected={selectedOption === 'syncTitles'}
|
|
242
|
-
onSelect={setSelectedOption}
|
|
243
|
-
title="Sync all titles"
|
|
244
|
-
count={videosToUpdate}
|
|
245
|
-
description="Replaces the title in Sanity with the title from Mux for all videos."
|
|
246
|
-
disabled={isResyncing}
|
|
247
|
-
/>
|
|
248
|
-
|
|
249
|
-
<OptionCard
|
|
250
|
-
id="fullResync"
|
|
251
|
-
selected={selectedOption === 'fullResync'}
|
|
252
|
-
onSelect={setSelectedOption}
|
|
253
|
-
title="Full resync"
|
|
254
|
-
count={videosToUpdate}
|
|
255
|
-
description="Updates all fields from Mux including status, duration, tracks, captions, and renditions."
|
|
256
|
-
disabled={isResyncing}
|
|
257
|
-
/>
|
|
258
|
-
</Stack>
|
|
259
|
-
</Stack>
|
|
260
|
-
)}
|
|
261
|
-
</Box>
|
|
262
|
-
</Dialog>
|
|
263
|
-
)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export default function ResyncMetadata() {
|
|
267
|
-
const resyncMetadata = useResyncMuxMetadata()
|
|
268
|
-
|
|
269
|
-
if (!resyncMetadata.hasSecrets) {
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (resyncMetadata.dialogOpen) {
|
|
274
|
-
return <ResyncMetadataDialog {...resyncMetadata} />
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return <Button mode="bleed" text="Sync with Mux" onClick={resyncMetadata.openDialog} />
|
|
278
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import {useCallback} from 'react'
|
|
2
|
-
import {PatchEvent, set, setIfMissing, unset} from 'sanity'
|
|
3
|
-
|
|
4
|
-
import type {SetDialogState} from '../hooks/useDialogState'
|
|
5
|
-
import type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'
|
|
6
|
-
import VideosBrowser, {type VideosBrowserProps} from './VideosBrowser'
|
|
7
|
-
|
|
8
|
-
export interface Props extends Pick<MuxInputProps, 'onChange'> {
|
|
9
|
-
asset?: VideoAssetDocument | null | undefined
|
|
10
|
-
setDialogState: SetDialogState
|
|
11
|
-
config: PluginConfig
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default function SelectAssets({
|
|
15
|
-
asset: selectedAsset,
|
|
16
|
-
onChange,
|
|
17
|
-
setDialogState,
|
|
18
|
-
config,
|
|
19
|
-
}: Props) {
|
|
20
|
-
const handleSelect = useCallback<Required<VideosBrowserProps>['onSelect']>(
|
|
21
|
-
(chosenAsset) => {
|
|
22
|
-
if (!chosenAsset?._id) {
|
|
23
|
-
onChange(PatchEvent.from([unset(['asset'])]))
|
|
24
|
-
}
|
|
25
|
-
if (chosenAsset._id !== selectedAsset?._id) {
|
|
26
|
-
onChange(
|
|
27
|
-
PatchEvent.from([
|
|
28
|
-
setIfMissing({asset: {}, _type: 'mux.video'}),
|
|
29
|
-
set({_type: 'reference', _weak: true, _ref: chosenAsset._id}, ['asset']),
|
|
30
|
-
]),
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
setDialogState(false)
|
|
34
|
-
},
|
|
35
|
-
[onChange, setDialogState, selectedAsset],
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
return <VideosBrowser onSelect={handleSelect} config={config} />
|
|
39
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {SortIcon} from '@sanity/icons'
|
|
2
|
-
import {Button, Menu, MenuButton, MenuItem, type PopoverProps} from '@sanity/ui'
|
|
3
|
-
import {useId} from 'react'
|
|
4
|
-
|
|
5
|
-
import {ASSET_SORT_OPTIONS, type SortOption} from '../hooks/useAssets'
|
|
6
|
-
|
|
7
|
-
const CONTEXT_MENU_POPOVER_PROPS: PopoverProps = {
|
|
8
|
-
constrainSize: true,
|
|
9
|
-
placement: 'bottom',
|
|
10
|
-
portal: true,
|
|
11
|
-
width: 0,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @sanity/ui components adapted from:
|
|
16
|
-
* https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/pane/PaneContextMenuButton.tsx#L19
|
|
17
|
-
*/
|
|
18
|
-
export function SelectSortOptions(props: {sort: SortOption; setSort: (s: SortOption) => void}) {
|
|
19
|
-
const id = useId()
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<MenuButton
|
|
23
|
-
button={
|
|
24
|
-
<Button text="Sort" icon={SortIcon} mode="bleed" padding={3} style={{cursor: 'pointer'}} />
|
|
25
|
-
}
|
|
26
|
-
id={id}
|
|
27
|
-
menu={
|
|
28
|
-
<Menu>
|
|
29
|
-
{Object.entries(ASSET_SORT_OPTIONS).map(([type, {label}]) => (
|
|
30
|
-
<MenuItem
|
|
31
|
-
key={type}
|
|
32
|
-
data-as="button"
|
|
33
|
-
onClick={() => props.setSort(type as SortOption)}
|
|
34
|
-
padding={3}
|
|
35
|
-
tone="default"
|
|
36
|
-
text={label}
|
|
37
|
-
pressed={type === props.sort}
|
|
38
|
-
/>
|
|
39
|
-
))}
|
|
40
|
-
</Menu>
|
|
41
|
-
}
|
|
42
|
-
popover={CONTEXT_MENU_POPOVER_PROPS}
|
|
43
|
-
/>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {Box, Spinner} from '@sanity/ui'
|
|
2
|
-
|
|
3
|
-
const SpinnerBox: React.FC = () => (
|
|
4
|
-
<Box
|
|
5
|
-
style={{
|
|
6
|
-
display: 'flex',
|
|
7
|
-
alignItems: 'center',
|
|
8
|
-
justifyContent: 'center',
|
|
9
|
-
minHeight: '150px',
|
|
10
|
-
}}
|
|
11
|
-
>
|
|
12
|
-
<Spinner />
|
|
13
|
-
</Box>
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
export default SpinnerBox
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type {Tool} from 'sanity'
|
|
2
|
-
|
|
3
|
-
import type {PluginConfig} from '../util/types'
|
|
4
|
-
import ToolIcon from './icons/ToolIcon'
|
|
5
|
-
import VideosBrowser from './VideosBrowser'
|
|
6
|
-
|
|
7
|
-
const StudioTool: React.FC<PluginConfig> = (config) => {
|
|
8
|
-
return <VideosBrowser config={config} />
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const DEFAULT_TOOL_CONFIG = {
|
|
12
|
-
icon: ToolIcon,
|
|
13
|
-
title: 'Videos',
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default function createStudioTool(config: PluginConfig): Tool {
|
|
17
|
-
const toolConfig = typeof config.tool === 'object' ? config.tool : DEFAULT_TOOL_CONFIG
|
|
18
|
-
return {
|
|
19
|
-
name: 'mux',
|
|
20
|
-
icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,
|
|
21
|
-
title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,
|
|
22
|
-
component: (props: any) => <StudioTool {...config} {...props} />,
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import {TranslateIcon} from '@sanity/icons'
|
|
2
|
-
import {Autocomplete, Box, Card, Checkbox, Flex, Stack, Text} from '@sanity/ui'
|
|
3
|
-
import {uuid} from '@sanity/uuid'
|
|
4
|
-
import LanguagesList from 'iso-639-1'
|
|
5
|
-
import {type Dispatch} from 'react'
|
|
6
|
-
import {FormField} from 'sanity'
|
|
7
|
-
|
|
8
|
-
import {type PluginConfig, SUPPORTED_MUX_LANGUAGES, type UploadTextTrack} from '../util/types'
|
|
9
|
-
|
|
10
|
-
const ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({
|
|
11
|
-
value: code,
|
|
12
|
-
label: LanguagesList.getNativeName(code),
|
|
13
|
-
}))
|
|
14
|
-
|
|
15
|
-
const SUBTITLE_LANGUAGES: Record<
|
|
16
|
-
Extract<UploadTextTrack, {language_code: any}>['type'],
|
|
17
|
-
{value: string; label: string}[]
|
|
18
|
-
> = {
|
|
19
|
-
autogenerated: SUPPORTED_MUX_LANGUAGES.map((lang) => ({
|
|
20
|
-
value: lang.code,
|
|
21
|
-
label: lang.label,
|
|
22
|
-
})),
|
|
23
|
-
subtitles: ALL_LANGUAGE_CODES,
|
|
24
|
-
captions: ALL_LANGUAGE_CODES,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type TrackSubAction =
|
|
28
|
-
| {subAction: 'add'; value: Partial<UploadTextTrack>}
|
|
29
|
-
| {subAction: 'update'; value: Partial<UploadTextTrack>}
|
|
30
|
-
| {subAction: 'delete'}
|
|
31
|
-
|
|
32
|
-
export type TrackAction = {action: 'track'; id: string} & TrackSubAction
|
|
33
|
-
|
|
34
|
-
export default function TextTracksEditor({
|
|
35
|
-
tracks,
|
|
36
|
-
dispatch,
|
|
37
|
-
defaultLang,
|
|
38
|
-
}: {
|
|
39
|
-
/**
|
|
40
|
-
* Although the schema for tracks is an array, which we'll eventually support to allow uploading
|
|
41
|
-
* multiple custom subtitles, for now we only support a single auto-generated track.
|
|
42
|
-
*/
|
|
43
|
-
tracks: (Partial<UploadTextTrack> & {_id: string})[]
|
|
44
|
-
dispatch: Dispatch<TrackAction>
|
|
45
|
-
defaultLang: PluginConfig['defaultAutogeneratedSubtitleLang']
|
|
46
|
-
}) {
|
|
47
|
-
const track = tracks[0]
|
|
48
|
-
return (
|
|
49
|
-
<FormField title="Auto-generated subtitle or caption" path={[]}>
|
|
50
|
-
<Stack space={2}>
|
|
51
|
-
<Flex align="center">
|
|
52
|
-
<Checkbox
|
|
53
|
-
id="include-autogenerated-track"
|
|
54
|
-
style={{display: 'block'}}
|
|
55
|
-
checked={!!track?.language_code}
|
|
56
|
-
onChange={() => {
|
|
57
|
-
if (track) {
|
|
58
|
-
dispatch({action: 'track', id: track._id, subAction: 'delete'})
|
|
59
|
-
} else {
|
|
60
|
-
dispatch({
|
|
61
|
-
action: 'track',
|
|
62
|
-
id: uuid(),
|
|
63
|
-
subAction: 'add',
|
|
64
|
-
value: {
|
|
65
|
-
type: 'autogenerated',
|
|
66
|
-
name: defaultLang || undefined,
|
|
67
|
-
language_code: defaultLang || undefined,
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
}}
|
|
72
|
-
/>
|
|
73
|
-
<Box flex={1} paddingLeft={3}>
|
|
74
|
-
<Text>
|
|
75
|
-
<label htmlFor="checkbox">Generate captions</label>
|
|
76
|
-
</Text>
|
|
77
|
-
</Box>
|
|
78
|
-
</Flex>
|
|
79
|
-
{track && (
|
|
80
|
-
<Autocomplete
|
|
81
|
-
id={`text-tract-editor--language`}
|
|
82
|
-
value={track.language_code}
|
|
83
|
-
onChange={(newValue) =>
|
|
84
|
-
dispatch({
|
|
85
|
-
action: 'track',
|
|
86
|
-
id: track._id,
|
|
87
|
-
subAction: 'update',
|
|
88
|
-
value: {
|
|
89
|
-
language_code: newValue,
|
|
90
|
-
name: LanguagesList.getNativeName(newValue),
|
|
91
|
-
},
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
options={SUBTITLE_LANGUAGES[track.type!]}
|
|
95
|
-
icon={TranslateIcon}
|
|
96
|
-
placeholder="Select language"
|
|
97
|
-
filterOption={(query, option) =>
|
|
98
|
-
option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
|
|
99
|
-
option.value.toLowerCase().indexOf(query.toLowerCase()) > -1
|
|
100
|
-
}
|
|
101
|
-
openButton
|
|
102
|
-
renderValue={(value) =>
|
|
103
|
-
SUBTITLE_LANGUAGES[track.type!].find((l) => l.value === value)?.label || value
|
|
104
|
-
}
|
|
105
|
-
renderOption={(option) => (
|
|
106
|
-
<Card data-as="button" padding={3} radius={2} tone="inherit">
|
|
107
|
-
<Text size={2} textOverflow="ellipsis">
|
|
108
|
-
{option.label} ({option.value})
|
|
109
|
-
</Text>
|
|
110
|
-
</Card>
|
|
111
|
-
)}
|
|
112
|
-
/>
|
|
113
|
-
)}
|
|
114
|
-
</Stack>
|
|
115
|
-
</FormField>
|
|
116
|
-
)
|
|
117
|
-
}
|