sanity-plugin-mux-input 2.1.1 → 2.2.1
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/README.md +1 -1
- package/lib/index.cjs +4038 -4
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +14 -1
- package/lib/index.js +4027 -2
- package/lib/index.js.map +1 -1
- package/package.json +30 -30
- package/src/actions/assets.ts +30 -2
- package/src/components/ConfigureApi.tsx +9 -1
- package/src/components/FormField.tsx +8 -10
- package/src/components/IconInfo.tsx +23 -0
- package/src/components/Input.styled.tsx +0 -8
- package/src/components/Input.tsx +4 -3
- package/src/components/InputBrowser.tsx +1 -8
- package/src/components/Player.styled.tsx +5 -144
- package/src/components/Player.tsx +23 -109
- package/src/components/PlayerActionsMenu.tsx +0 -4
- package/src/components/SelectAsset.tsx +18 -58
- package/src/components/SelectSortOptions.tsx +45 -0
- package/src/components/SpinnerBox.tsx +17 -0
- package/src/components/StudioTool.tsx +20 -0
- package/src/components/VideoDetails/DeleteDialog.tsx +156 -0
- package/src/components/VideoDetails/VideoDetails.tsx +298 -0
- package/src/components/VideoDetails/VideoReferences.tsx +70 -0
- package/src/components/VideoDetails/useVideoDetails.ts +85 -0
- package/src/components/VideoInBrowser.tsx +183 -0
- package/src/components/VideoMetadata.tsx +43 -0
- package/src/components/VideoPlayer.tsx +69 -0
- package/src/components/VideoThumbnail.tsx +106 -0
- package/src/components/VideosBrowser.tsx +83 -0
- package/src/components/__legacy__Uploader.tsx +2 -9
- package/src/components/documentPreview/DocumentPreview.tsx +107 -0
- package/src/components/documentPreview/DraftStatus.tsx +34 -0
- package/src/components/documentPreview/MissingSchemaType.tsx +33 -0
- package/src/components/documentPreview/PaneItemPreview.tsx +71 -0
- package/src/components/documentPreview/PublishedStatus.tsx +35 -0
- package/src/components/documentPreview/TimeAgo.tsx +13 -0
- package/src/components/documentPreview/paneItemTypes.ts +7 -0
- package/src/components/icons/Resolution.tsx +12 -0
- package/src/components/icons/StopWatch.tsx +20 -0
- package/src/components/icons/ToolIcon.tsx +21 -0
- package/src/hooks/useAssets.ts +61 -0
- package/src/hooks/useCancelUpload.ts +2 -2
- package/src/hooks/useClient.ts +3 -1
- package/src/hooks/useDocReferences.ts +21 -0
- package/src/hooks/useInView.ts +45 -0
- package/src/index.ts +2 -0
- package/src/plugin.tsx +1 -1
- package/src/util/constants.ts +7 -0
- package/src/util/createSearchFilter.ts +78 -0
- package/src/util/formatSeconds.ts +22 -0
- package/src/util/getAnimatedPosterSrc.ts +1 -1
- package/src/util/getPlaybackId.ts +1 -1
- package/src/util/getPlaybackPolicy.ts +1 -1
- package/src/util/getVideoMetadata.ts +18 -0
- package/src/util/types.ts +16 -1
- package/lib/_chunks/Player-547f8e2a.cjs +0 -474
- package/lib/_chunks/Player-547f8e2a.cjs.map +0 -1
- package/lib/_chunks/Player-bfdb96f6.js +0 -465
- package/lib/_chunks/Player-bfdb96f6.js.map +0 -1
- package/lib/_chunks/index-39e38243.cjs +0 -3251
- package/lib/_chunks/index-39e38243.cjs.map +0 -1
- package/lib/_chunks/index-71899191.js +0 -3229
- package/lib/_chunks/index-71899191.js.map +0 -1
- package/src/components/EditThumbnailDialog.tsx +0 -74
- package/src/components/VideoSource.styled.tsx +0 -235
- package/src/components/VideoSource.tsx +0 -318
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-mux-input",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -61,62 +61,61 @@
|
|
|
61
61
|
"watch": "pkg-utils watch --strict"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@mux/mux-
|
|
64
|
+
"@mux/mux-player-react": "^1.11.4",
|
|
65
65
|
"@mux/upchunk": "^3",
|
|
66
66
|
"@sanity/icons": "^2",
|
|
67
67
|
"@sanity/incompatible-plugin": "^1",
|
|
68
68
|
"@sanity/ui": "^1",
|
|
69
69
|
"@sanity/uuid": "^3",
|
|
70
|
-
"classnames": "^2.3.2",
|
|
71
70
|
"jsonwebtoken-esm": "^1.0.5",
|
|
72
|
-
"
|
|
73
|
-
"
|
|
71
|
+
"lodash": "^4",
|
|
72
|
+
"react-rx": "^2.1.3",
|
|
74
73
|
"rxjs": "^7",
|
|
75
74
|
"scroll-into-view-if-needed": "^3",
|
|
76
|
-
"suspend-react": "^0.0
|
|
75
|
+
"suspend-react": "^0.1.0",
|
|
77
76
|
"swr": "^2.1.0",
|
|
78
|
-
"
|
|
77
|
+
"type-fest": "^4.0.0",
|
|
79
78
|
"use-error-boundary": "^2.0.6"
|
|
80
79
|
},
|
|
81
80
|
"devDependencies": {
|
|
82
|
-
"@commitlint/cli": "^17.
|
|
83
|
-
"@commitlint/config-conventional": "^17.
|
|
84
|
-
"@sanity/pkg-utils": "^2.
|
|
81
|
+
"@commitlint/cli": "^17.6.7",
|
|
82
|
+
"@commitlint/config-conventional": "^17.6.7",
|
|
83
|
+
"@sanity/pkg-utils": "^2.3.10",
|
|
85
84
|
"@sanity/plugin-kit": "^3.1.7",
|
|
86
|
-
"@sanity/semantic-release-preset": "^4.
|
|
87
|
-
"@sanity/vision": "^3.
|
|
88
|
-
"@types/react": "^18.
|
|
85
|
+
"@sanity/semantic-release-preset": "^4.1.2",
|
|
86
|
+
"@sanity/vision": "^3.14.5",
|
|
87
|
+
"@types/react": "^18.2.18",
|
|
89
88
|
"@types/styled-components": "^5.1.26",
|
|
90
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
91
|
-
"@typescript-eslint/parser": "^5.
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
90
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
92
91
|
"cz-conventional-changelog": "^3.3.0",
|
|
93
|
-
"eslint": "^8.
|
|
94
|
-
"eslint-config-prettier": "^8.
|
|
92
|
+
"eslint": "^8.46.0",
|
|
93
|
+
"eslint-config-prettier": "^8.10.0",
|
|
95
94
|
"eslint-config-react-app": "^7.0.1",
|
|
96
95
|
"eslint-config-sanity": "^6.0.0",
|
|
97
|
-
"eslint-plugin-import": "^2.
|
|
98
|
-
"eslint-plugin-prettier": "^
|
|
99
|
-
"eslint-plugin-react": "^7.
|
|
96
|
+
"eslint-plugin-import": "^2.28.0",
|
|
97
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
98
|
+
"eslint-plugin-react": "^7.33.1",
|
|
100
99
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
101
100
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
102
101
|
"husky": "^8.0.3",
|
|
103
|
-
"lint-staged": "^13.2.
|
|
104
|
-
"next": "^13.
|
|
105
|
-
"next-sanity": "^
|
|
102
|
+
"lint-staged": "^13.2.3",
|
|
103
|
+
"next": "^13.4.12",
|
|
104
|
+
"next-sanity": "^5.1.3",
|
|
106
105
|
"npm-run-all": "^4.1.5",
|
|
107
|
-
"prettier": "^
|
|
108
|
-
"prettier-plugin-packagejson": "^2.4.
|
|
106
|
+
"prettier": "^3.0.1",
|
|
107
|
+
"prettier-plugin-packagejson": "^2.4.5",
|
|
109
108
|
"react": "^18.2.0",
|
|
110
109
|
"react-dom": "^18.2.0",
|
|
111
110
|
"react-is": "^18.2.0",
|
|
112
111
|
"rimraf": "^5.0.0",
|
|
113
|
-
"sanity": "^3.
|
|
114
|
-
"styled-components": "^5.3.
|
|
115
|
-
"
|
|
116
|
-
"typescript": "^5.0.2"
|
|
112
|
+
"sanity": "^3.14.5",
|
|
113
|
+
"styled-components": "^5.3.11",
|
|
114
|
+
"typescript": "^5.1.6"
|
|
117
115
|
},
|
|
118
116
|
"peerDependencies": {
|
|
119
117
|
"react": "^18",
|
|
118
|
+
"react-is": "^18",
|
|
120
119
|
"sanity": "^3",
|
|
121
120
|
"styled-components": "^5.2"
|
|
122
121
|
},
|
|
@@ -124,7 +123,8 @@
|
|
|
124
123
|
"node": ">=14"
|
|
125
124
|
},
|
|
126
125
|
"publishConfig": {
|
|
127
|
-
"access": "public"
|
|
126
|
+
"access": "public",
|
|
127
|
+
"provenance": true
|
|
128
128
|
},
|
|
129
129
|
"sanityExchangeUrl": "https://www.sanity.io/plugins/sanity-plugin-mux-input"
|
|
130
130
|
}
|
package/src/actions/assets.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {SanityClient} from 'sanity'
|
|
2
2
|
|
|
3
|
-
import type {MuxAsset} from '../util/types'
|
|
3
|
+
import type {MuxAsset, VideoAssetDocument} from '../util/types'
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function deleteAssetOnMux(client: SanityClient, assetId: string) {
|
|
6
6
|
const {dataset} = client.config()
|
|
7
7
|
return client.request<void>({
|
|
8
8
|
url: `/addons/mux/assets/${dataset}/${assetId}`,
|
|
@@ -11,6 +11,34 @@ export function deleteAsset(client: SanityClient, assetId: string) {
|
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export async function deleteAsset({
|
|
15
|
+
client,
|
|
16
|
+
asset,
|
|
17
|
+
deleteOnMux,
|
|
18
|
+
}: {
|
|
19
|
+
client: SanityClient
|
|
20
|
+
asset: VideoAssetDocument
|
|
21
|
+
deleteOnMux: boolean
|
|
22
|
+
}) {
|
|
23
|
+
if (!asset?._id) return true
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
await client.delete(asset._id)
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return 'failed-sanity'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (deleteOnMux && asset?.assetId) {
|
|
32
|
+
try {
|
|
33
|
+
await deleteAssetOnMux(client, asset.assetId)
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return 'failed-mux'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
14
42
|
export function getAsset(client: SanityClient, assetId: string) {
|
|
15
43
|
const {dataset} = client.config()
|
|
16
44
|
return client.request<{data: MuxAsset}>({
|
|
@@ -108,7 +108,15 @@ function ConfigureApi({secrets, setDialogState}: Props) {
|
|
|
108
108
|
}, [firstField])
|
|
109
109
|
|
|
110
110
|
return (
|
|
111
|
-
<Dialog
|
|
111
|
+
<Dialog
|
|
112
|
+
id={id}
|
|
113
|
+
onClose={handleClose}
|
|
114
|
+
header={<Header />}
|
|
115
|
+
width={1}
|
|
116
|
+
style={{
|
|
117
|
+
maxWidth: '550px',
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
112
120
|
<Box padding={4} style={{position: 'relative'}}>
|
|
113
121
|
<form onSubmit={handleSubmit} noValidate>
|
|
114
122
|
<Stack space={4}>
|
|
@@ -18,17 +18,15 @@ function FormField(props: Props) {
|
|
|
18
18
|
<Flex align="flex-end">
|
|
19
19
|
<Box flex={1} paddingY={2}>
|
|
20
20
|
<Stack space={2}>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</Text>
|
|
21
|
+
<Text as="label" htmlFor={inputId} weight="semibold" size={1}>
|
|
22
|
+
{title || <em>Untitled</em>}
|
|
23
|
+
</Text>
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
</Flex>
|
|
25
|
+
{description && (
|
|
26
|
+
<Text muted size={1}>
|
|
27
|
+
{description}
|
|
28
|
+
</Text>
|
|
29
|
+
)}
|
|
32
30
|
</Stack>
|
|
33
31
|
</Box>
|
|
34
32
|
</Flex>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {Flex, Text} from '@sanity/ui'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
const IconInfo: React.FC<{
|
|
5
|
+
text: string
|
|
6
|
+
icon: React.FC
|
|
7
|
+
size?: number
|
|
8
|
+
muted?: boolean
|
|
9
|
+
}> = (props) => {
|
|
10
|
+
const Icon = props.icon
|
|
11
|
+
return (
|
|
12
|
+
<Flex gap={2} align="center" padding={1}>
|
|
13
|
+
<Text size={(props.size || 1) + 1} muted>
|
|
14
|
+
<Icon />
|
|
15
|
+
</Text>
|
|
16
|
+
<Text size={props.size || 1} muted={props.muted}>
|
|
17
|
+
{props.text}
|
|
18
|
+
</Text>
|
|
19
|
+
</Flex>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default IconInfo
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import {Box, Card, Flex, Spinner, Text} from '@sanity/ui'
|
|
2
2
|
import React from 'react'
|
|
3
|
-
import styled from 'styled-components'
|
|
4
|
-
|
|
5
|
-
// This container base container ensures everything uses the same aspect ratio, avoids layout shifts and stuff jumping around
|
|
6
|
-
export const AspectRatioCard = styled(Card)`
|
|
7
|
-
aspect-ratio: 16 / 9;
|
|
8
|
-
position: relative;
|
|
9
|
-
width: 100%;
|
|
10
|
-
`
|
|
11
3
|
|
|
12
4
|
export const InputFallback = () => {
|
|
13
5
|
return (
|
package/src/components/Input.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Card} from '@sanity/ui'
|
|
1
2
|
import React, {memo, Suspense} from 'react'
|
|
2
3
|
|
|
3
4
|
import {useAssetDocumentValues} from '../hooks/useAssetDocumentValues'
|
|
@@ -9,7 +10,7 @@ import type {Config, MuxInputProps} from '../util/types'
|
|
|
9
10
|
import Uploader from './__legacy__Uploader'
|
|
10
11
|
import ConfigureApi from './ConfigureApi'
|
|
11
12
|
import ErrorBoundaryCard from './ErrorBoundaryCard'
|
|
12
|
-
import {
|
|
13
|
+
import {InputFallback} from './Input.styled'
|
|
13
14
|
import Onboard from './Onboard'
|
|
14
15
|
|
|
15
16
|
export interface InputProps extends MuxInputProps {
|
|
@@ -35,7 +36,7 @@ const Input = (props: InputProps) => {
|
|
|
35
36
|
const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading
|
|
36
37
|
|
|
37
38
|
return (
|
|
38
|
-
<
|
|
39
|
+
<Card>
|
|
39
40
|
<ErrorBoundaryCard schemaType={props.schemaType}>
|
|
40
41
|
<Suspense fallback={<InputFallback />}>
|
|
41
42
|
{isLoading ? (
|
|
@@ -68,7 +69,7 @@ const Input = (props: InputProps) => {
|
|
|
68
69
|
)}
|
|
69
70
|
</Suspense>
|
|
70
71
|
</ErrorBoundaryCard>
|
|
71
|
-
</
|
|
72
|
+
</Card>
|
|
72
73
|
)
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -11,14 +11,7 @@ export default function InputBrowser({setDialogState, asset, onChange}: Props) {
|
|
|
11
11
|
const id = `InputBrowser${useId()}`
|
|
12
12
|
const handleClose = useCallback(() => setDialogState(false), [setDialogState])
|
|
13
13
|
return (
|
|
14
|
-
<Dialog
|
|
15
|
-
scheme="dark"
|
|
16
|
-
__unstable_autoFocus
|
|
17
|
-
header="Select video"
|
|
18
|
-
id={id}
|
|
19
|
-
onClose={handleClose}
|
|
20
|
-
width={2}
|
|
21
|
-
>
|
|
14
|
+
<Dialog __unstable_autoFocus header="Select video" id={id} onClose={handleClose} width={2}>
|
|
22
15
|
<SelectAsset asset={asset} onChange={onChange} setDialogState={setDialogState} />
|
|
23
16
|
</Dialog>
|
|
24
17
|
)
|
|
@@ -1,131 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {MediaControlBar, MediaPosterImage} from 'media-chrome/dist/react'
|
|
3
|
-
import React, {useEffect, useMemo, useRef, useState} from 'react'
|
|
1
|
+
import {useState} from 'react'
|
|
4
2
|
import styled from 'styled-components'
|
|
5
3
|
|
|
6
4
|
import {useClient} from '../hooks/useClient'
|
|
7
|
-
import {getPosterSrc} from '../util/getPosterSrc'
|
|
8
5
|
import {getStoryboardSrc} from '../util/getStoryboardSrc'
|
|
9
6
|
import type {VideoAssetDocument} from '../util/types'
|
|
10
7
|
|
|
11
|
-
export const VideoContainer = styled(Card)`
|
|
12
|
-
position: relative;
|
|
13
|
-
min-height: 150px;
|
|
14
|
-
aspect-ratio: 16 / 9;
|
|
15
|
-
overflow: hidden;
|
|
16
|
-
border-radius: 1px;
|
|
17
|
-
media-airplay-button[media-airplay-unavailable] {
|
|
18
|
-
display: none;
|
|
19
|
-
}
|
|
20
|
-
media-volume-range[media-volume-unavailable] {
|
|
21
|
-
display: none;
|
|
22
|
-
}
|
|
23
|
-
media-pip-button[media-pip-unavailable] {
|
|
24
|
-
display: none;
|
|
25
|
-
}
|
|
26
|
-
media-controller {
|
|
27
|
-
--media-control-background: transparent;
|
|
28
|
-
--media-control-hover-background: transparent;
|
|
29
|
-
--media-range-track-background-color: rgba(255, 255, 255, 0.5);
|
|
30
|
-
--media-range-track-border-radius: 3px;
|
|
31
|
-
width: 100%;
|
|
32
|
-
height: 100%;
|
|
33
|
-
background-color: transparent;
|
|
34
|
-
}
|
|
35
|
-
media-control-bar {
|
|
36
|
-
--media-button-icon-width: 18px;
|
|
37
|
-
--media-preview-time-margin: 0px;
|
|
38
|
-
}
|
|
39
|
-
media-control-bar:not([slot]) :is([role='button'], [role='switch'], button) {
|
|
40
|
-
height: 44px;
|
|
41
|
-
}
|
|
42
|
-
.size-extra-small media-control-bar [role='button'],
|
|
43
|
-
.size-extra-small media-control-bar [role='switch'] {
|
|
44
|
-
height: auto;
|
|
45
|
-
padding: 4.4% 3.2%;
|
|
46
|
-
}
|
|
47
|
-
.mxp-spacer {
|
|
48
|
-
flex-grow: 1;
|
|
49
|
-
height: 100%;
|
|
50
|
-
background-color: var(--media-control-background, rgba(20, 20, 30, 0.7));
|
|
51
|
-
}
|
|
52
|
-
media-controller::part(vertical-layer) {
|
|
53
|
-
transition: background-color 1s;
|
|
54
|
-
}
|
|
55
|
-
media-controller:is([media-paused], :not([user-inactive]))::part(vertical-layer) {
|
|
56
|
-
background-color: rgba(0, 0, 0, 0.6);
|
|
57
|
-
transition: background-color 0.25s;
|
|
58
|
-
}
|
|
59
|
-
.mxp-center-controls {
|
|
60
|
-
--media-background-color: transparent;
|
|
61
|
-
--media-button-icon-width: 100%;
|
|
62
|
-
--media-button-icon-height: auto;
|
|
63
|
-
pointer-events: none;
|
|
64
|
-
width: 100%;
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-flow: row;
|
|
67
|
-
align-items: center;
|
|
68
|
-
justify-content: center;
|
|
69
|
-
}
|
|
70
|
-
.mxp-center-controls media-play-button {
|
|
71
|
-
--media-control-background: transparent;
|
|
72
|
-
--media-control-hover-background: transparent;
|
|
73
|
-
padding: 0;
|
|
74
|
-
width: max(27px, min(9%, 90px));
|
|
75
|
-
}
|
|
76
|
-
.mxp-center-controls media-seek-backward-button,
|
|
77
|
-
.mxp-center-controls media-seek-forward-button {
|
|
78
|
-
--media-control-background: transparent;
|
|
79
|
-
--media-control-hover-background: transparent;
|
|
80
|
-
padding: 0;
|
|
81
|
-
margin: 0 10%;
|
|
82
|
-
width: min(7%, 70px);
|
|
83
|
-
}
|
|
84
|
-
media-loading-indicator {
|
|
85
|
-
--media-loading-icon-width: 100%;
|
|
86
|
-
--media-button-icon-height: auto;
|
|
87
|
-
pointer-events: none;
|
|
88
|
-
position: absolute;
|
|
89
|
-
width: min(15%, 150px);
|
|
90
|
-
display: flex;
|
|
91
|
-
flex-flow: row;
|
|
92
|
-
align-items: center;
|
|
93
|
-
justify-content: center;
|
|
94
|
-
}
|
|
95
|
-
/* Intentionally don't target the div for transition but the children
|
|
96
|
-
of the div. Prevents messing with media-chrome's autohide feature. */
|
|
97
|
-
media-loading-indicator + div * {
|
|
98
|
-
transition: opacity 0.15s;
|
|
99
|
-
opacity: 1;
|
|
100
|
-
}
|
|
101
|
-
media-loading-indicator[media-loading]:not([media-paused]) ~ div > * {
|
|
102
|
-
opacity: 0;
|
|
103
|
-
transition-delay: 400ms;
|
|
104
|
-
}
|
|
105
|
-
media-volume-range {
|
|
106
|
-
width: min(100%, 100px);
|
|
107
|
-
}
|
|
108
|
-
media-time-display {
|
|
109
|
-
white-space: nowrap;
|
|
110
|
-
}
|
|
111
|
-
:is(media-time-display, media-text-display, media-playback-rate-button) {
|
|
112
|
-
color: inherit;
|
|
113
|
-
}
|
|
114
|
-
media-controller:fullscreen media-control-bar[slot='top-chrome'] {
|
|
115
|
-
/* Hide menus and buttons that trigger modals when in full-screen */
|
|
116
|
-
display: none;
|
|
117
|
-
}
|
|
118
|
-
video {
|
|
119
|
-
background: transparent;
|
|
120
|
-
}
|
|
121
|
-
media-controller:not(:fullscreen) video {
|
|
122
|
-
aspect-ratio: 16 / 9;
|
|
123
|
-
}
|
|
124
|
-
media-controller:not(:-webkit-full-screen) video {
|
|
125
|
-
aspect-ratio: 16 / 9;
|
|
126
|
-
}
|
|
127
|
-
`
|
|
128
|
-
|
|
129
8
|
export const StyledCenterControls = styled.div`
|
|
130
9
|
&& {
|
|
131
10
|
--media-background-color: transparent;
|
|
@@ -146,7 +25,10 @@ export const StyledCenterControls = styled.div`
|
|
|
146
25
|
}
|
|
147
26
|
`
|
|
148
27
|
|
|
149
|
-
export const TopControls = styled
|
|
28
|
+
export const TopControls = styled.div`
|
|
29
|
+
position: absolute;
|
|
30
|
+
top: 0;
|
|
31
|
+
right: 0;
|
|
150
32
|
justify-content: flex-end;
|
|
151
33
|
button {
|
|
152
34
|
height: auto;
|
|
@@ -156,27 +38,6 @@ export const TopControls = styled(MediaControlBar)`
|
|
|
156
38
|
export interface PosterImageProps {
|
|
157
39
|
asset: VideoAssetDocument
|
|
158
40
|
}
|
|
159
|
-
export function PosterImage({asset}: PosterImageProps) {
|
|
160
|
-
const client = useClient()
|
|
161
|
-
const ref = useRef<HTMLElement>(null)
|
|
162
|
-
const src = useMemo(
|
|
163
|
-
() => getPosterSrc({client, asset, width: 1920, height: 1080}),
|
|
164
|
-
[client, asset]
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
useEffect(() => {
|
|
168
|
-
if (ref.current) {
|
|
169
|
-
const style = document.createElement('style')
|
|
170
|
-
style.innerHTML = 'img { object-fit: contain; }'
|
|
171
|
-
if (ref.current?.shadowRoot) {
|
|
172
|
-
ref.current.shadowRoot.appendChild(style)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}, [])
|
|
176
|
-
|
|
177
|
-
return <MediaPosterImage ref={ref} slot="poster" src={src} />
|
|
178
|
-
}
|
|
179
|
-
|
|
180
41
|
export interface ThumbnailsMetadataTrackProps {
|
|
181
42
|
asset: VideoAssetDocument
|
|
182
43
|
}
|
|
@@ -1,43 +1,18 @@
|
|
|
1
|
-
import MuxVideo from '@mux/mux-video-react'
|
|
2
1
|
import {Card, Text} from '@sanity/ui'
|
|
3
|
-
import {
|
|
4
|
-
MediaControlBar,
|
|
5
|
-
MediaController,
|
|
6
|
-
MediaDurationDisplay,
|
|
7
|
-
MediaFullscreenButton,
|
|
8
|
-
MediaLoadingIndicator,
|
|
9
|
-
MediaMuteButton,
|
|
10
|
-
MediaPlayButton,
|
|
11
|
-
MediaTimeDisplay,
|
|
12
|
-
MediaTimeRange,
|
|
13
|
-
} from 'media-chrome/dist/react'
|
|
14
|
-
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
|
2
|
+
import React, {useEffect, useMemo, useRef} from 'react'
|
|
15
3
|
|
|
16
4
|
import {useCancelUpload} from '../hooks/useCancelUpload'
|
|
17
|
-
import {useClient} from '../hooks/useClient'
|
|
18
|
-
import type {DialogState, SetDialogState} from '../hooks/useDialogState'
|
|
19
|
-
import {getVideoSrc} from '../util/getVideoSrc'
|
|
20
5
|
import type {MuxInputProps, VideoAssetDocument} from '../util/types'
|
|
21
|
-
import
|
|
22
|
-
import EditThumbnailDialog from './EditThumbnailDialog'
|
|
23
|
-
import {
|
|
24
|
-
PosterImage,
|
|
25
|
-
StyledCenterControls,
|
|
26
|
-
ThumbnailsMetadataTrack,
|
|
27
|
-
TopControls,
|
|
28
|
-
VideoContainer,
|
|
29
|
-
} from './Player.styled'
|
|
6
|
+
import {TopControls} from './Player.styled'
|
|
30
7
|
import {UploadProgress} from './UploadProgress'
|
|
8
|
+
import VideoPlayer from './VideoPlayer'
|
|
31
9
|
|
|
32
10
|
interface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {
|
|
33
11
|
buttons?: React.ReactNode
|
|
34
12
|
asset: VideoAssetDocument
|
|
35
|
-
dialogState: DialogState
|
|
36
|
-
setDialogState: SetDialogState
|
|
37
13
|
}
|
|
38
14
|
|
|
39
|
-
const
|
|
40
|
-
const client = useClient()
|
|
15
|
+
const Player = ({asset, buttons, readOnly, onChange}: Props) => {
|
|
41
16
|
const isLoading = useMemo<boolean | string>(() => {
|
|
42
17
|
if (asset?.status === 'preparing') {
|
|
43
18
|
return 'Preparing the video'
|
|
@@ -66,16 +41,8 @@ const MuxVideoOld = ({asset, buttons, readOnly, onChange, dialogState, setDialog
|
|
|
66
41
|
}
|
|
67
42
|
return false
|
|
68
43
|
}, [asset?.data?.static_renditions?.status])
|
|
69
|
-
const videoSrc = useMemo(() => asset.playbackId && getVideoSrc({client, asset}), [asset, client])
|
|
70
|
-
const [error, setError] = useState<MediaError | Error | null>(null)
|
|
71
|
-
const handleError = useCallback<React.ReactEventHandler<HTMLVideoElement>>(
|
|
72
|
-
(event) => setError(event.currentTarget.error),
|
|
73
|
-
[]
|
|
74
|
-
)
|
|
75
44
|
const playRef = useRef<HTMLDivElement>(null)
|
|
76
45
|
const muteRef = useRef<HTMLDivElement>(null)
|
|
77
|
-
const video = useRef<HTMLVideoElement>(null)
|
|
78
|
-
const getCurrentTime = useCallback(() => video.current?.currentTime ?? 0, [video])
|
|
79
46
|
const handleCancelUpload = useCancelUpload(asset, onChange)
|
|
80
47
|
|
|
81
48
|
useEffect(() => {
|
|
@@ -99,20 +66,6 @@ const MuxVideoOld = ({asset, buttons, readOnly, onChange, dialogState, setDialog
|
|
|
99
66
|
}
|
|
100
67
|
}, [asset.data?.errors?.messages, asset?.status, handleCancelUpload])
|
|
101
68
|
|
|
102
|
-
const signedToken = useMemo(() => {
|
|
103
|
-
try {
|
|
104
|
-
const url = new URL(videoSrc!)
|
|
105
|
-
return url.searchParams.get('token')
|
|
106
|
-
} catch {
|
|
107
|
-
return false
|
|
108
|
-
}
|
|
109
|
-
}, [videoSrc])
|
|
110
|
-
|
|
111
|
-
if (error) {
|
|
112
|
-
// @TODO better error handling
|
|
113
|
-
throw error
|
|
114
|
-
}
|
|
115
|
-
|
|
116
69
|
if (!asset || !asset.status) {
|
|
117
70
|
return null
|
|
118
71
|
}
|
|
@@ -129,65 +82,26 @@ const MuxVideoOld = ({asset, buttons, readOnly, onChange, dialogState, setDialog
|
|
|
129
82
|
}
|
|
130
83
|
|
|
131
84
|
return (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
<ThumbnailsMetadataTrack asset={asset} />
|
|
150
|
-
</MuxVideo>
|
|
151
|
-
<PosterImage asset={asset} />
|
|
152
|
-
<MediaLoadingIndicator slot="centered-chrome" noAutoHide />
|
|
153
|
-
<StyledCenterControls slot="centered-chrome">
|
|
154
|
-
<MediaPlayButton />
|
|
155
|
-
</StyledCenterControls>
|
|
156
|
-
{buttons && <TopControls slot="top-chrome">{buttons}</TopControls>}
|
|
157
|
-
<MediaControlBar>
|
|
158
|
-
<MediaMuteButton />
|
|
159
|
-
<MediaTimeDisplay />
|
|
160
|
-
<MediaTimeRange />
|
|
161
|
-
<MediaDurationDisplay />
|
|
162
|
-
<MediaFullscreenButton />
|
|
163
|
-
</MediaControlBar>
|
|
164
|
-
</MediaController>
|
|
165
|
-
{isPreparingStaticRenditions && (
|
|
166
|
-
<Card
|
|
167
|
-
padding={2}
|
|
168
|
-
radius={1}
|
|
169
|
-
style={{
|
|
170
|
-
background: 'var(--card-fg-color)',
|
|
171
|
-
position: 'absolute',
|
|
172
|
-
top: '0.5em',
|
|
173
|
-
left: '0.5em',
|
|
174
|
-
}}
|
|
175
|
-
>
|
|
176
|
-
<Text size={1} style={{color: 'var(--card-bg-color)'}}>
|
|
177
|
-
MUX is preparing static renditions, please stand by
|
|
178
|
-
</Text>
|
|
179
|
-
</Card>
|
|
180
|
-
)}
|
|
181
|
-
</VideoContainer>
|
|
182
|
-
{dialogState === 'edit-thumbnail' && (
|
|
183
|
-
<EditThumbnailDialog
|
|
184
|
-
asset={asset}
|
|
185
|
-
getCurrentTime={getCurrentTime}
|
|
186
|
-
setDialogState={setDialogState}
|
|
187
|
-
/>
|
|
85
|
+
<VideoPlayer asset={asset}>
|
|
86
|
+
{buttons && <TopControls slot="top-chrome">{buttons}</TopControls>}
|
|
87
|
+
{isPreparingStaticRenditions && (
|
|
88
|
+
<Card
|
|
89
|
+
padding={2}
|
|
90
|
+
radius={1}
|
|
91
|
+
style={{
|
|
92
|
+
background: 'var(--card-fg-color)',
|
|
93
|
+
position: 'absolute',
|
|
94
|
+
top: '0.5em',
|
|
95
|
+
left: '0.5em',
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
<Text size={1} style={{color: 'var(--card-bg-color)'}}>
|
|
99
|
+
MUX is preparing static renditions, please stand by
|
|
100
|
+
</Text>
|
|
101
|
+
</Card>
|
|
188
102
|
)}
|
|
189
|
-
|
|
103
|
+
</VideoPlayer>
|
|
190
104
|
)
|
|
191
105
|
}
|
|
192
106
|
|
|
193
|
-
export default
|
|
107
|
+
export default Player
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
EditIcon,
|
|
3
2
|
EllipsisVerticalIcon,
|
|
4
3
|
LockIcon,
|
|
5
4
|
PlugIcon,
|
|
@@ -88,9 +87,6 @@ function PlayerActionsMenu(props: Props) {
|
|
|
88
87
|
</LockCard>
|
|
89
88
|
</Tooltip>
|
|
90
89
|
)}
|
|
91
|
-
{!readOnly && (
|
|
92
|
-
<Button icon={EditIcon} mode="ghost" onClick={() => setDialogState('edit-thumbnail')} />
|
|
93
|
-
)}
|
|
94
90
|
<Popover
|
|
95
91
|
content={
|
|
96
92
|
<Menu ref={setMenuRef}>
|