sanity-plugin-mux-input 2.16.0 → 2.17.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 +866 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +866 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/actions/upload.ts +42 -4
- package/src/components/DraggableWatermark.tsx +877 -0
- package/src/components/UploadConfiguration.tsx +259 -59
- package/src/components/Uploader.tsx +7 -1
- package/src/components/VideoPlayer.tsx +2 -0
- package/src/hooks/useMediaMetadata.ts +3 -0
- package/src/util/convertWatermarkToMux.ts +160 -0
- package/src/util/roundPxString.ts +16 -0
- package/src/util/types.ts +43 -1
package/dist/index.js
CHANGED
|
@@ -974,7 +974,7 @@ function tryWithSuspend(block, onError) {
|
|
|
974
974
|
return onError ? onError(errorOrPromise) : void 0;
|
|
975
975
|
}
|
|
976
976
|
}
|
|
977
|
-
const Image = styledComponents.styled.img`
|
|
977
|
+
const Image$1 = styledComponents.styled.img`
|
|
978
978
|
transition: opacity 0.175s ease-out 0s;
|
|
979
979
|
display: block;
|
|
980
980
|
width: 100%;
|
|
@@ -1052,7 +1052,7 @@ function VideoThumbnail({
|
|
|
1052
1052
|
}
|
|
1053
1053
|
),
|
|
1054
1054
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1055
|
-
Image,
|
|
1055
|
+
Image$1,
|
|
1056
1056
|
{
|
|
1057
1057
|
src: thumbnailSrc ?? void 0,
|
|
1058
1058
|
alt: `Preview for ${staticImage ? "image" : "video"} ${asset.filename || asset.assetId}`,
|
|
@@ -3060,7 +3060,7 @@ function VideoPlayer({
|
|
|
3060
3060
|
hlsConfig,
|
|
3061
3061
|
...props
|
|
3062
3062
|
}) {
|
|
3063
|
-
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = React.useRef(null), [error, setError] = React.useState(), playbackId = React.useMemo(() => {
|
|
3063
|
+
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = React.useRef(null), playerContainerRef = React.useRef(null), [error, setError] = React.useState(), playbackId = React.useMemo(() => {
|
|
3064
3064
|
try {
|
|
3065
3065
|
return getPlaybackId(asset, ["public", "signed", "drm"]);
|
|
3066
3066
|
} catch {
|
|
@@ -3118,6 +3118,7 @@ function VideoPlayer({
|
|
|
3118
3118
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3119
3119
|
ui.Card,
|
|
3120
3120
|
{
|
|
3121
|
+
ref: playerContainerRef,
|
|
3121
3122
|
tone: "transparent",
|
|
3122
3123
|
style: {
|
|
3123
3124
|
aspectRatio,
|
|
@@ -3154,7 +3155,7 @@ function VideoPlayer({
|
|
|
3154
3155
|
crossOrigin: "anonymous",
|
|
3155
3156
|
metadata: {
|
|
3156
3157
|
player_name: "Sanity Admin Dashboard",
|
|
3157
|
-
player_version: "2.
|
|
3158
|
+
player_version: "2.17.0",
|
|
3158
3159
|
page_type: "Preview Player"
|
|
3159
3160
|
},
|
|
3160
3161
|
audio: isAudio,
|
|
@@ -4316,6 +4317,33 @@ function createUpChunkObservable(uuid2, uploadUrl2, source) {
|
|
|
4316
4317
|
return upchunk$1.on("success", successHandler), upchunk$1.on("error", errorHandler), upchunk$1.on("progress", progressHandler), upchunk$1.on("offline", offlineHandler), upchunk$1.on("online", onlineHandler), () => upchunk$1.abort();
|
|
4317
4318
|
});
|
|
4318
4319
|
}
|
|
4320
|
+
function roundPxString(value) {
|
|
4321
|
+
if (typeof value != "string") return;
|
|
4322
|
+
const trimmed = value.trim();
|
|
4323
|
+
if (!trimmed.endsWith("px")) return;
|
|
4324
|
+
const n = Number(trimmed.slice(0, -2));
|
|
4325
|
+
if (!Number.isFinite(n)) return;
|
|
4326
|
+
let rounded = Math.round(n);
|
|
4327
|
+
return rounded === 0 && (rounded = n < 0 ? -1 : 1), `${rounded}px`;
|
|
4328
|
+
}
|
|
4329
|
+
function sanitizeOverlaySettingsInPlace(settings) {
|
|
4330
|
+
const inputs = settings.input;
|
|
4331
|
+
if (inputs)
|
|
4332
|
+
for (const input of inputs) {
|
|
4333
|
+
const overlay = input.overlay_settings;
|
|
4334
|
+
if (!overlay) continue;
|
|
4335
|
+
const hm = roundPxString(overlay.horizontal_margin), vm = roundPxString(overlay.vertical_margin), w = roundPxString(overlay.width);
|
|
4336
|
+
hm && (overlay.horizontal_margin = hm), vm && (overlay.vertical_margin = vm), w && (overlay.width = w);
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
function sanitizePxStringsInJson(json) {
|
|
4340
|
+
return json.replace(/"(-?\d+(?:\.\d+)?)px"/g, (_match, num) => {
|
|
4341
|
+
const n = Number(num);
|
|
4342
|
+
if (!Number.isFinite(n)) return _match;
|
|
4343
|
+
let rounded = Math.round(n);
|
|
4344
|
+
return rounded === 0 && (rounded = n < 0 ? -1 : 1), `"${rounded}px"`;
|
|
4345
|
+
});
|
|
4346
|
+
}
|
|
4319
4347
|
function cancelUpload(client, uuid2) {
|
|
4320
4348
|
return client.observable.request({
|
|
4321
4349
|
url: `/addons/mux/uploads/${client.config().dataset}/${uuid2}`,
|
|
@@ -4326,7 +4354,8 @@ function cancelUpload(client, uuid2) {
|
|
|
4326
4354
|
function uploadUrl({
|
|
4327
4355
|
url,
|
|
4328
4356
|
settings,
|
|
4329
|
-
client
|
|
4357
|
+
client,
|
|
4358
|
+
watermark
|
|
4330
4359
|
}) {
|
|
4331
4360
|
return testUrl(url).pipe(
|
|
4332
4361
|
operators.switchMap((validUrl) => rxjs.concat(
|
|
@@ -4336,9 +4365,9 @@ function uploadUrl({
|
|
|
4336
4365
|
if (!json || !json.status)
|
|
4337
4366
|
return rxjs.throwError(new Error("Invalid credentials"));
|
|
4338
4367
|
const uuid$1 = uuid.uuid(), muxBody = settings;
|
|
4339
|
-
muxBody.input || (muxBody.input = [{ type: "video" }]), muxBody.input[0].url = validUrl;
|
|
4368
|
+
muxBody.input || (muxBody.input = [{ type: "video" }]), muxBody.input[0].url = validUrl, sanitizeOverlaySettingsInPlace(muxBody);
|
|
4340
4369
|
const query = {
|
|
4341
|
-
muxBody: JSON.stringify(muxBody),
|
|
4370
|
+
muxBody: sanitizePxStringsInJson(JSON.stringify(muxBody)),
|
|
4342
4371
|
filename: validUrl.split("/").slice(-1)[0]
|
|
4343
4372
|
}, dataset = client.config().dataset;
|
|
4344
4373
|
return rxjs.defer(
|
|
@@ -4366,7 +4395,8 @@ function uploadUrl({
|
|
|
4366
4395
|
function uploadFile({
|
|
4367
4396
|
settings,
|
|
4368
4397
|
client,
|
|
4369
|
-
file
|
|
4398
|
+
file,
|
|
4399
|
+
watermark
|
|
4370
4400
|
}) {
|
|
4371
4401
|
return testFile(file).pipe(
|
|
4372
4402
|
operators.switchMap((fileOptions) => rxjs.concat(
|
|
@@ -4376,7 +4406,7 @@ function uploadFile({
|
|
|
4376
4406
|
if (!json || !json.status)
|
|
4377
4407
|
return rxjs.throwError(() => new Error("Invalid credentials"));
|
|
4378
4408
|
const uuid$1 = uuid.uuid(), body = settings;
|
|
4379
|
-
return rxjs.concat(
|
|
4409
|
+
return sanitizeOverlaySettingsInPlace(body), rxjs.concat(
|
|
4380
4410
|
rxjs.of({ type: "uuid", uuid: uuid$1 }),
|
|
4381
4411
|
rxjs.defer(
|
|
4382
4412
|
() => client.observable.request({
|
|
@@ -4430,7 +4460,7 @@ function pollUpload(client, uuid2) {
|
|
|
4430
4460
|
}, 2e3);
|
|
4431
4461
|
});
|
|
4432
4462
|
}
|
|
4433
|
-
async function updateAssetDocumentFromUpload(client, uuid2) {
|
|
4463
|
+
async function updateAssetDocumentFromUpload(client, uuid2, _watermark) {
|
|
4434
4464
|
let upload, asset;
|
|
4435
4465
|
try {
|
|
4436
4466
|
upload = await pollUpload(client, uuid2);
|
|
@@ -4952,13 +4982,14 @@ function useMediaMetadata(stagedUpload) {
|
|
|
4952
4982
|
setIsLoadingMetadata(!1);
|
|
4953
4983
|
},
|
|
4954
4984
|
() => {
|
|
4955
|
-
const duration = videoElement.duration, width = videoElement.videoWidth, height = videoElement.videoHeight, isAudioOnly = width <= 0 && height <= 0;
|
|
4985
|
+
const duration = videoElement.duration, width = videoElement.videoWidth, height = videoElement.videoHeight, isAudioOnly = width <= 0 && height <= 0, aspectRatio = width / height;
|
|
4956
4986
|
setVideoAssetMetadata((old) => ({
|
|
4957
4987
|
...old,
|
|
4958
4988
|
duration,
|
|
4959
4989
|
width,
|
|
4960
4990
|
height,
|
|
4961
|
-
isAudioOnly
|
|
4991
|
+
isAudioOnly,
|
|
4992
|
+
aspectRatio
|
|
4962
4993
|
}));
|
|
4963
4994
|
}
|
|
4964
4995
|
], cleanupVideo = (videoEl) => {
|
|
@@ -4980,6 +5011,51 @@ function useMediaMetadata(stagedUpload) {
|
|
|
4980
5011
|
isLoadingMetadata
|
|
4981
5012
|
};
|
|
4982
5013
|
}
|
|
5014
|
+
function convertWatermarkToMuxOverlay(watermark, options) {
|
|
5015
|
+
if (!watermark.enabled || !watermark.imageUrl)
|
|
5016
|
+
return null;
|
|
5017
|
+
const size = watermark.size || 20, opacity = watermark.opacity ?? 0.7, toPxString = (valuePercent, axis) => {
|
|
5018
|
+
const videoAspectRatio2 = options?.videoAspectRatio ?? 1.7777777777777777, isVertical = videoAspectRatio2 > 0 && videoAspectRatio2 < 1, base = axis === "x" ? isVertical ? 1080 : 1920 : isVertical ? 1920 : 1080, px = valuePercent / 100 * base;
|
|
5019
|
+
let rounded = Math.round(px);
|
|
5020
|
+
return rounded === 0 && (rounded = px < 0 ? -1 : 1), `${rounded}px`;
|
|
5021
|
+
}, normalizeToPixels = (value, axis) => {
|
|
5022
|
+
if (!value) return value;
|
|
5023
|
+
const trimmed = value.trim();
|
|
5024
|
+
if (trimmed.endsWith("px"))
|
|
5025
|
+
return roundPxString(trimmed);
|
|
5026
|
+
if (trimmed.endsWith("%")) {
|
|
5027
|
+
const n = Number(trimmed.slice(0, -1));
|
|
5028
|
+
return Number.isFinite(n) ? toPxString(n, axis) : value;
|
|
5029
|
+
}
|
|
5030
|
+
return value;
|
|
5031
|
+
};
|
|
5032
|
+
if (watermark.overlay_settings) {
|
|
5033
|
+
const widthValue = watermark.overlay_settings.width, widthNormalized = options?.units === "px" ? normalizeToPixels(widthValue, "x") : widthValue;
|
|
5034
|
+
return {
|
|
5035
|
+
...watermark.overlay_settings,
|
|
5036
|
+
horizontal_margin: options?.units === "px" ? normalizeToPixels(watermark.overlay_settings.horizontal_margin, "x") ?? watermark.overlay_settings.horizontal_margin : watermark.overlay_settings.horizontal_margin,
|
|
5037
|
+
vertical_margin: options?.units === "px" ? normalizeToPixels(watermark.overlay_settings.vertical_margin, "y") ?? watermark.overlay_settings.vertical_margin : watermark.overlay_settings.vertical_margin,
|
|
5038
|
+
width: widthNormalized ?? `${size}%`,
|
|
5039
|
+
opacity: watermark.overlay_settings.opacity ?? `${Math.round(opacity * 100)}%`
|
|
5040
|
+
};
|
|
5041
|
+
}
|
|
5042
|
+
const position = watermark.position || { x: 50, y: 50 }, clampPercent = (value) => Math.max(-100, Math.min(100, value)), toPercentString = (value) => `${value === 0 || Object.is(value, -0) || Math.abs(value) < 1e-9 ? 0.01 : value}%`, watermarkWidthPercentOfVideoWidth = size, videoAspectRatio = options?.videoAspectRatio ?? 16 / 9, imageAspectRatio = watermark.imageAspectRatio ?? 1, watermarkHeightPercentOfVideoHeight = Math.max(
|
|
5043
|
+
0,
|
|
5044
|
+
Math.min(100, size * videoAspectRatio / imageAspectRatio)
|
|
5045
|
+
), halfWidth = watermarkWidthPercentOfVideoWidth / 2, halfHeight = watermarkHeightPercentOfVideoHeight / 2, leftMargin = clampPercent(
|
|
5046
|
+
Math.min(position.x - halfWidth, 100 - watermarkWidthPercentOfVideoWidth)
|
|
5047
|
+
), topMargin = clampPercent(
|
|
5048
|
+
Math.min(position.y - halfHeight, 100 - watermarkHeightPercentOfVideoHeight)
|
|
5049
|
+
), units = options?.units ?? "%", marginX = units === "px" ? toPxString(leftMargin, "x") : toPercentString(leftMargin), marginY = units === "px" ? toPxString(topMargin, "y") : toPercentString(topMargin), width = units === "px" ? toPxString(size, "x") : `${size}%`;
|
|
5050
|
+
return {
|
|
5051
|
+
vertical_align: "top",
|
|
5052
|
+
vertical_margin: marginY,
|
|
5053
|
+
horizontal_align: "left",
|
|
5054
|
+
horizontal_margin: marginX,
|
|
5055
|
+
width,
|
|
5056
|
+
opacity: `${Math.round(opacity * 100)}%`
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
4983
5059
|
function formatBytes(bytes, si = !1, dp = 1) {
|
|
4984
5060
|
const thresh = si ? 1e3 : 1024;
|
|
4985
5061
|
if (Math.abs(bytes) < thresh)
|
|
@@ -4992,6 +5068,566 @@ function formatBytes(bytes, si = !1, dp = 1) {
|
|
|
4992
5068
|
while (Math.round(Math.abs(bytes) * r) / r >= thresh && u2 < units.length - 1);
|
|
4993
5069
|
return bytes.toFixed(dp) + " " + units[u2];
|
|
4994
5070
|
}
|
|
5071
|
+
const RangeInput = styledComponents.styled.input`
|
|
5072
|
+
width: 100%;
|
|
5073
|
+
height: 4px;
|
|
5074
|
+
border-radius: 2px;
|
|
5075
|
+
background: var(--card-border-color);
|
|
5076
|
+
outline: none;
|
|
5077
|
+
-webkit-appearance: none;
|
|
5078
|
+
appearance: none;
|
|
5079
|
+
|
|
5080
|
+
&::-webkit-slider-thumb {
|
|
5081
|
+
-webkit-appearance: none;
|
|
5082
|
+
appearance: none;
|
|
5083
|
+
width: 16px;
|
|
5084
|
+
height: 16px;
|
|
5085
|
+
border-radius: 50%;
|
|
5086
|
+
background: var(--card-focus-ring-color, #2276fc);
|
|
5087
|
+
cursor: pointer;
|
|
5088
|
+
border: 2px solid white;
|
|
5089
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
5090
|
+
}
|
|
5091
|
+
|
|
5092
|
+
&::-moz-range-thumb {
|
|
5093
|
+
width: 16px;
|
|
5094
|
+
height: 16px;
|
|
5095
|
+
border-radius: 50%;
|
|
5096
|
+
background: var(--card-focus-ring-color, #2276fc);
|
|
5097
|
+
cursor: pointer;
|
|
5098
|
+
border: 2px solid white;
|
|
5099
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
5100
|
+
}
|
|
5101
|
+
|
|
5102
|
+
&:hover::-webkit-slider-thumb {
|
|
5103
|
+
background: var(--card-focus-ring-color, #1a5fc7);
|
|
5104
|
+
}
|
|
5105
|
+
|
|
5106
|
+
&:hover::-moz-range-thumb {
|
|
5107
|
+
background: var(--card-focus-ring-color, #1a5fc7);
|
|
5108
|
+
}
|
|
5109
|
+
`, WatermarkOverlay = styledComponents.styled.div`
|
|
5110
|
+
position: absolute;
|
|
5111
|
+
max-width: 200px;
|
|
5112
|
+
opacity: ${(props) => props.$opacity};
|
|
5113
|
+
cursor: move;
|
|
5114
|
+
user-select: none;
|
|
5115
|
+
z-index: 10;
|
|
5116
|
+
pointer-events: auto;
|
|
5117
|
+
|
|
5118
|
+
img {
|
|
5119
|
+
width: 100%;
|
|
5120
|
+
height: auto;
|
|
5121
|
+
display: block;
|
|
5122
|
+
pointer-events: none;
|
|
5123
|
+
}
|
|
5124
|
+
|
|
5125
|
+
&:hover {
|
|
5126
|
+
outline: 2px dashed rgba(255, 255, 255, 0.8);
|
|
5127
|
+
outline-offset: 4px;
|
|
5128
|
+
}
|
|
5129
|
+
`;
|
|
5130
|
+
function DraggableWatermark({
|
|
5131
|
+
watermark,
|
|
5132
|
+
onChange,
|
|
5133
|
+
containerRef,
|
|
5134
|
+
videoElementRef
|
|
5135
|
+
}) {
|
|
5136
|
+
const [isDragging, setIsDragging] = React.useState(!1), [dragStart, setDragStart] = React.useState({ x: 0, y: 0 }), [startPosition, setStartPosition] = React.useState({ x: 0, y: 0 }), watermarkRef = React.useRef(null), debounceTimeoutRef = React.useRef(null), [localPosition, setLocalPosition] = React.useState(watermark.position || { x: 50, y: 50 }), position = localPosition, size = watermark.size || 20, opacity = watermark.opacity ?? 0.7, parseOpacityPercent = (value) => {
|
|
5137
|
+
if (!value) return null;
|
|
5138
|
+
const trimmed = value.trim();
|
|
5139
|
+
if (!trimmed.endsWith("%")) return null;
|
|
5140
|
+
const num = Number(trimmed.slice(0, -1));
|
|
5141
|
+
return Number.isFinite(num) ? Math.max(0, Math.min(1, num / 100)) : null;
|
|
5142
|
+
}, getVideoContentBox = React.useCallback(() => {
|
|
5143
|
+
const container = containerRef?.current;
|
|
5144
|
+
if (!container) return { x: 0, y: 0, width: 0, height: 0 };
|
|
5145
|
+
const rect = container.getBoundingClientRect(), containerW = rect.width, containerH = rect.height, videoEl = videoElementRef?.current, videoW = videoEl?.videoWidth || 0, videoH = videoEl?.videoHeight || 0;
|
|
5146
|
+
if (!videoW || !videoH || !containerW || !containerH)
|
|
5147
|
+
return { x: 0, y: 0, width: containerW, height: containerH };
|
|
5148
|
+
const scale = Math.min(containerW / videoW, containerH / videoH), contentW = videoW * scale, contentH = videoH * scale, offsetX = (containerW - contentW) / 2, offsetY = (containerH - contentH) / 2;
|
|
5149
|
+
return { x: offsetX, y: offsetY, width: contentW, height: contentH };
|
|
5150
|
+
}, [containerRef, videoElementRef]), parseOverlayValue = (value) => {
|
|
5151
|
+
if (!value) return null;
|
|
5152
|
+
const trimmed = value.trim(), px = trimmed.endsWith("px"), pct = trimmed.endsWith("%"), num = Number(trimmed.replace(/px|%/g, ""));
|
|
5153
|
+
return Number.isFinite(num) ? px ? { n: num, unit: "px" } : pct ? { n: num, unit: "%" } : null : null;
|
|
5154
|
+
}, computeManualStyle = (overlay) => {
|
|
5155
|
+
const rect = containerRef?.current?.getBoundingClientRect(), w = rect?.width ?? 0, h = rect?.height ?? 0, isVertical = h > w, baseW = isVertical ? 1080 : 1920, baseH = isVertical ? 1920 : 1080, hm = parseOverlayValue(overlay.horizontal_margin), vm = parseOverlayValue(overlay.vertical_margin), ww = parseOverlayValue(overlay.width), manualOpacity = parseOpacityPercent(overlay.opacity), toCss = (v, axis) => {
|
|
5156
|
+
if (v)
|
|
5157
|
+
return v.unit === "%" ? `${v.n}%` : axis === "x" ? `${v.n * w / baseW}px` : `${v.n * h / baseH}px`;
|
|
5158
|
+
}, computeHorizontalStyle = () => overlay.horizontal_align === "left" ? { left: toCss(hm, "x"), right: void 0, transform: "translate(0, 0)" } : overlay.horizontal_align === "right" ? { right: toCss(hm, "x"), left: void 0, transform: "translate(0, 0)" } : { left: "50%", right: void 0, transform: "translate(-50%, 0)" }, computeVerticalStyle = () => overlay.vertical_align === "top" ? { top: toCss(vm, "y"), bottom: void 0 } : overlay.vertical_align === "bottom" ? { bottom: toCss(vm, "y"), top: void 0 } : { top: "50%", bottom: void 0 }, hStyle = computeHorizontalStyle(), vStyle = computeVerticalStyle();
|
|
5159
|
+
let transform = hStyle.transform;
|
|
5160
|
+
return overlay.vertical_align === "middle" && (transform = overlay.horizontal_align === "center" ? "translate(-50%, -50%)" : "translate(0, -50%)"), {
|
|
5161
|
+
position: "absolute",
|
|
5162
|
+
...hStyle,
|
|
5163
|
+
...vStyle,
|
|
5164
|
+
transform,
|
|
5165
|
+
width: ww ? toCss(ww, "x") : `${size}%`,
|
|
5166
|
+
opacity: manualOpacity ?? opacity,
|
|
5167
|
+
cursor: "default"
|
|
5168
|
+
};
|
|
5169
|
+
}, debouncedOnChange = React.useCallback(
|
|
5170
|
+
(newWatermark) => {
|
|
5171
|
+
debounceTimeoutRef.current && clearTimeout(debounceTimeoutRef.current), debounceTimeoutRef.current = setTimeout(() => {
|
|
5172
|
+
onChange(newWatermark);
|
|
5173
|
+
}, 300);
|
|
5174
|
+
},
|
|
5175
|
+
[onChange]
|
|
5176
|
+
);
|
|
5177
|
+
React.useEffect(() => () => {
|
|
5178
|
+
debounceTimeoutRef.current && clearTimeout(debounceTimeoutRef.current);
|
|
5179
|
+
}, []), React.useEffect(() => {
|
|
5180
|
+
!isDragging && watermark.position && setLocalPosition(watermark.position);
|
|
5181
|
+
}, [watermark.position, isDragging]);
|
|
5182
|
+
const handleMouseDown = React.useCallback(
|
|
5183
|
+
(e) => {
|
|
5184
|
+
e.preventDefault(), setIsDragging(!0), setDragStart({ x: e.clientX, y: e.clientY }), setStartPosition({ x: position.x, y: position.y });
|
|
5185
|
+
},
|
|
5186
|
+
[position]
|
|
5187
|
+
), handleMouseMove = React.useCallback(
|
|
5188
|
+
(e) => {
|
|
5189
|
+
if (!isDragging || !containerRef?.current) return;
|
|
5190
|
+
const rect = containerRef.current.getBoundingClientRect(), content = getVideoContentBox(), contentW = content.width || rect.width, contentH = content.height || rect.height, dx = e.clientX - dragStart.x, dy = e.clientY - dragStart.y, deltaXPercent = dx / contentW * 100, deltaYPercent = dy / contentH * 100;
|
|
5191
|
+
let newX = startPosition.x + deltaXPercent, newY = startPosition.y + deltaYPercent;
|
|
5192
|
+
newX = Math.max(0, Math.min(100, newX)), newY = Math.max(0, Math.min(100, newY)), setLocalPosition({ x: newX, y: newY }), debouncedOnChange({
|
|
5193
|
+
...watermark,
|
|
5194
|
+
position: { x: newX, y: newY }
|
|
5195
|
+
});
|
|
5196
|
+
},
|
|
5197
|
+
[
|
|
5198
|
+
isDragging,
|
|
5199
|
+
dragStart,
|
|
5200
|
+
startPosition,
|
|
5201
|
+
containerRef,
|
|
5202
|
+
watermark,
|
|
5203
|
+
debouncedOnChange,
|
|
5204
|
+
getVideoContentBox
|
|
5205
|
+
]
|
|
5206
|
+
), handleMouseUp = React.useCallback(() => {
|
|
5207
|
+
setIsDragging(!1), debounceTimeoutRef.current && (clearTimeout(debounceTimeoutRef.current), debounceTimeoutRef.current = null), onChange({
|
|
5208
|
+
...watermark,
|
|
5209
|
+
position: localPosition
|
|
5210
|
+
});
|
|
5211
|
+
}, [watermark, localPosition, onChange]);
|
|
5212
|
+
if (React.useEffect(() => {
|
|
5213
|
+
if (isDragging)
|
|
5214
|
+
return document.addEventListener("mousemove", handleMouseMove), document.addEventListener("mouseup", handleMouseUp), () => {
|
|
5215
|
+
document.removeEventListener("mousemove", handleMouseMove), document.removeEventListener("mouseup", handleMouseUp);
|
|
5216
|
+
};
|
|
5217
|
+
}, [isDragging, handleMouseMove, handleMouseUp]), !watermark.imageUrl)
|
|
5218
|
+
return null;
|
|
5219
|
+
const hasManualOverlay = !!watermark.overlay_settings, opacityForRender = hasManualOverlay ? parseOpacityPercent(watermark.overlay_settings?.opacity) ?? opacity : opacity, contentBox = getVideoContentBox(), hasContentBox = contentBox.width > 0 && contentBox.height > 0;
|
|
5220
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5221
|
+
WatermarkOverlay,
|
|
5222
|
+
{
|
|
5223
|
+
ref: watermarkRef,
|
|
5224
|
+
$opacity: opacityForRender,
|
|
5225
|
+
onMouseDown: hasManualOverlay ? void 0 : handleMouseDown,
|
|
5226
|
+
style: hasManualOverlay ? computeManualStyle(watermark.overlay_settings) : hasContentBox ? {
|
|
5227
|
+
left: `${contentBox.x + position.x / 100 * contentBox.width}px`,
|
|
5228
|
+
top: `${contentBox.y + position.y / 100 * contentBox.height}px`,
|
|
5229
|
+
transform: "translate(-50%, -50%)",
|
|
5230
|
+
width: `${Math.max(1, size / 100 * contentBox.width)}px`,
|
|
5231
|
+
cursor: isDragging ? "grabbing" : "grab"
|
|
5232
|
+
} : {
|
|
5233
|
+
left: `${position.x}%`,
|
|
5234
|
+
top: `${position.y}%`,
|
|
5235
|
+
transform: "translate(-50%, -50%)",
|
|
5236
|
+
width: `${size}%`,
|
|
5237
|
+
cursor: isDragging ? "grabbing" : "grab"
|
|
5238
|
+
},
|
|
5239
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: watermark.imageUrl, alt: "Watermark", draggable: !1 })
|
|
5240
|
+
}
|
|
5241
|
+
);
|
|
5242
|
+
}
|
|
5243
|
+
function WatermarkControls({
|
|
5244
|
+
watermark,
|
|
5245
|
+
onChange,
|
|
5246
|
+
onValidationChange,
|
|
5247
|
+
previewContainerRef,
|
|
5248
|
+
previewVideoRef
|
|
5249
|
+
}) {
|
|
5250
|
+
const [urlInput, setUrlInput] = React.useState(watermark.imageUrl || ""), [urlError, setUrlError] = React.useState(null), [isValidating, setIsValidating] = React.useState(!1), [isValid, setIsValid] = React.useState(null), validationTimeoutRef = React.useRef(null), [mode, setMode] = React.useState(
|
|
5251
|
+
watermark.overlay_settings ? "manual" : "canvas"
|
|
5252
|
+
), isUpdatingRef = React.useRef(!1), isValidExtension = (extension) => extension.endsWith(".png") || extension.endsWith(".jpg") || extension.endsWith(".jpeg"), validateUrl = React.useCallback(
|
|
5253
|
+
(url) => {
|
|
5254
|
+
if (validationTimeoutRef.current && clearTimeout(validationTimeoutRef.current), !url) {
|
|
5255
|
+
setUrlError(null), setIsValid(null), setIsValidating(!1), onValidationChange?.(null), isUpdatingRef.current = !0, onChange({
|
|
5256
|
+
...watermark,
|
|
5257
|
+
enabled: !1,
|
|
5258
|
+
imageUrl: void 0,
|
|
5259
|
+
overlay_settings: void 0
|
|
5260
|
+
});
|
|
5261
|
+
return;
|
|
5262
|
+
}
|
|
5263
|
+
setIsValidating(!0), setIsValid(null), setUrlError(null), validationTimeoutRef.current = setTimeout(() => {
|
|
5264
|
+
try {
|
|
5265
|
+
const pathname = new URL(url).pathname.toLowerCase();
|
|
5266
|
+
if (isValidExtension(pathname)) {
|
|
5267
|
+
setIsValid(!0), setUrlError(null), onValidationChange?.(null);
|
|
5268
|
+
const img = new Image();
|
|
5269
|
+
img.onload = () => {
|
|
5270
|
+
const imageAspectRatio = img.naturalWidth && img.naturalHeight ? img.naturalWidth / img.naturalHeight : 1;
|
|
5271
|
+
isUpdatingRef.current = !0, onChange({
|
|
5272
|
+
...watermark,
|
|
5273
|
+
enabled: !0,
|
|
5274
|
+
imageUrl: url,
|
|
5275
|
+
imageAspectRatio
|
|
5276
|
+
});
|
|
5277
|
+
}, img.onerror = () => {
|
|
5278
|
+
isUpdatingRef.current = !0, onChange({
|
|
5279
|
+
...watermark,
|
|
5280
|
+
enabled: !0,
|
|
5281
|
+
imageUrl: url,
|
|
5282
|
+
imageAspectRatio: watermark.imageAspectRatio
|
|
5283
|
+
});
|
|
5284
|
+
}, img.src = url;
|
|
5285
|
+
} else {
|
|
5286
|
+
const errorMsg = "Mux only supports PNG and JPG watermark images. Please use a .png or .jpg file.";
|
|
5287
|
+
setIsValid(!1), setUrlError(errorMsg), onValidationChange?.(errorMsg), isUpdatingRef.current = !0, onChange({
|
|
5288
|
+
...watermark,
|
|
5289
|
+
enabled: !1,
|
|
5290
|
+
imageUrl: void 0,
|
|
5291
|
+
imageAspectRatio: void 0,
|
|
5292
|
+
overlay_settings: void 0
|
|
5293
|
+
});
|
|
5294
|
+
}
|
|
5295
|
+
} catch {
|
|
5296
|
+
setIsValid(!1);
|
|
5297
|
+
const errorMsg = "Please enter a valid URL (e.g., https://example.com/watermark.png)";
|
|
5298
|
+
setUrlError(errorMsg), onValidationChange?.(errorMsg), isUpdatingRef.current = !0, onChange({
|
|
5299
|
+
...watermark,
|
|
5300
|
+
enabled: !1,
|
|
5301
|
+
imageUrl: void 0,
|
|
5302
|
+
imageAspectRatio: void 0,
|
|
5303
|
+
overlay_settings: void 0
|
|
5304
|
+
});
|
|
5305
|
+
} finally {
|
|
5306
|
+
setIsValidating(!1);
|
|
5307
|
+
}
|
|
5308
|
+
}, 500);
|
|
5309
|
+
},
|
|
5310
|
+
[watermark, onChange, onValidationChange]
|
|
5311
|
+
);
|
|
5312
|
+
React.useEffect(() => () => {
|
|
5313
|
+
validationTimeoutRef.current && clearTimeout(validationTimeoutRef.current);
|
|
5314
|
+
}, []), React.useEffect(() => {
|
|
5315
|
+
setMode(watermark.overlay_settings ? "manual" : "canvas");
|
|
5316
|
+
}, [watermark.overlay_settings]);
|
|
5317
|
+
const handleUrlChange = (e) => {
|
|
5318
|
+
const url = e.target.value;
|
|
5319
|
+
setUrlInput(url), watermark.imageUrl && url !== watermark.imageUrl && (isUpdatingRef.current = !0, onChange({
|
|
5320
|
+
...watermark,
|
|
5321
|
+
enabled: !1,
|
|
5322
|
+
imageUrl: void 0,
|
|
5323
|
+
imageAspectRatio: void 0,
|
|
5324
|
+
overlay_settings: void 0
|
|
5325
|
+
})), validateUrl(url);
|
|
5326
|
+
}, normalizeZeroPercent = (value) => {
|
|
5327
|
+
if (!value) return value;
|
|
5328
|
+
const trimmed = value.trim();
|
|
5329
|
+
if (!trimmed.endsWith("%")) return value;
|
|
5330
|
+
const n = Number(trimmed.slice(0, -1));
|
|
5331
|
+
return Number.isFinite(n) ? n === 0 || Object.is(n, -0) || Math.abs(n) < 1e-9 ? "0.01%" : `${n}%` : value;
|
|
5332
|
+
}, updateOverlaySettings = (next) => {
|
|
5333
|
+
const merged = {
|
|
5334
|
+
...watermark.overlay_settings ?? {
|
|
5335
|
+
vertical_align: "bottom",
|
|
5336
|
+
vertical_margin: "2%",
|
|
5337
|
+
horizontal_align: "right",
|
|
5338
|
+
horizontal_margin: "2%",
|
|
5339
|
+
width: `${watermark.size ?? 20}%`,
|
|
5340
|
+
opacity: `${Math.round((watermark.opacity ?? 0.7) * 100)}%`
|
|
5341
|
+
},
|
|
5342
|
+
...next
|
|
5343
|
+
};
|
|
5344
|
+
onChange({
|
|
5345
|
+
...watermark,
|
|
5346
|
+
enabled: !0,
|
|
5347
|
+
overlay_settings: {
|
|
5348
|
+
...merged,
|
|
5349
|
+
horizontal_margin: normalizeZeroPercent(merged.horizontal_margin) || merged.horizontal_margin,
|
|
5350
|
+
vertical_margin: normalizeZeroPercent(merged.vertical_margin) || merged.vertical_margin
|
|
5351
|
+
}
|
|
5352
|
+
});
|
|
5353
|
+
}, getVideoContentBox = () => {
|
|
5354
|
+
const container = previewContainerRef?.current;
|
|
5355
|
+
if (!container) return { x: 0, y: 0, width: 0, height: 0 };
|
|
5356
|
+
const rect = container.getBoundingClientRect(), containerW = rect.width, containerH = rect.height, videoEl = previewVideoRef?.current, videoW = videoEl?.videoWidth || 0, videoH = videoEl?.videoHeight || 0;
|
|
5357
|
+
if (!videoW || !videoH || !containerW || !containerH)
|
|
5358
|
+
return { x: 0, y: 0, width: containerW, height: containerH };
|
|
5359
|
+
const scale = Math.min(containerW / videoW, containerH / videoH), contentW = videoW * scale, contentH = videoH * scale, offsetX = (containerW - contentW) / 2, offsetY = (containerH - contentH) / 2;
|
|
5360
|
+
return { x: offsetX, y: offsetY, width: contentW, height: contentH };
|
|
5361
|
+
};
|
|
5362
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
5363
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
5364
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: "Watermark Image URL" }),
|
|
5365
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "Enter a URL to a PNG or JPG image. Mux will download this image and overlay it on your video." }),
|
|
5366
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { style: { position: "relative", width: "100%" }, children: [
|
|
5367
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5368
|
+
"input",
|
|
5369
|
+
{
|
|
5370
|
+
type: "url",
|
|
5371
|
+
value: urlInput,
|
|
5372
|
+
onChange: handleUrlChange,
|
|
5373
|
+
placeholder: "https://example.com/watermark.png",
|
|
5374
|
+
style: {
|
|
5375
|
+
padding: "8px 12px",
|
|
5376
|
+
paddingRight: urlInput ? "96px" : isValid !== null ? "36px" : "12px",
|
|
5377
|
+
border: urlError || isValid === !1 ? "1px solid #e74c3c" : isValid === !0 ? "1px solid #4caf50" : "1px solid #ccc",
|
|
5378
|
+
borderRadius: "4px",
|
|
5379
|
+
width: "100%",
|
|
5380
|
+
maxWidth: "100%",
|
|
5381
|
+
boxSizing: "border-box",
|
|
5382
|
+
fontSize: "14px"
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
),
|
|
5386
|
+
(urlInput || isValidating || isValid !== null) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5387
|
+
ui.Box,
|
|
5388
|
+
{
|
|
5389
|
+
style: {
|
|
5390
|
+
position: "absolute",
|
|
5391
|
+
right: "8px",
|
|
5392
|
+
top: "50%",
|
|
5393
|
+
transform: "translateY(-50%)",
|
|
5394
|
+
display: "flex",
|
|
5395
|
+
alignItems: "center",
|
|
5396
|
+
gap: "4px"
|
|
5397
|
+
},
|
|
5398
|
+
children: [
|
|
5399
|
+
urlInput && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5400
|
+
ui.Button,
|
|
5401
|
+
{
|
|
5402
|
+
text: "Clear",
|
|
5403
|
+
mode: "bleed",
|
|
5404
|
+
tone: "critical",
|
|
5405
|
+
onClick: () => {
|
|
5406
|
+
setUrlInput(""), validateUrl("");
|
|
5407
|
+
},
|
|
5408
|
+
disabled: isValidating,
|
|
5409
|
+
style: { fontSize: "11px", height: "24px" }
|
|
5410
|
+
}
|
|
5411
|
+
),
|
|
5412
|
+
isValidating && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "Validating..." }),
|
|
5413
|
+
isValid === !0 && !isValidating && /* @__PURE__ */ jsxRuntime.jsx(icons.CheckmarkCircleIcon, { style: { color: "#4caf50", fontSize: "18px" } }),
|
|
5414
|
+
isValid === !1 && !isValidating && /* @__PURE__ */ jsxRuntime.jsx(icons.ErrorOutlineIcon, { style: { color: "#e74c3c", fontSize: "18px" } })
|
|
5415
|
+
]
|
|
5416
|
+
}
|
|
5417
|
+
)
|
|
5418
|
+
] }),
|
|
5419
|
+
urlError && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 2, tone: "critical", radius: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 2, children: [
|
|
5420
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.ErrorOutlineIcon, { style: { color: "#e74c3c", flexShrink: 0 } }),
|
|
5421
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, style: { color: "#e74c3c" }, children: urlError })
|
|
5422
|
+
] }) })
|
|
5423
|
+
] }),
|
|
5424
|
+
watermark.imageUrl && /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
5425
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, tone: "transparent", border: !0, radius: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5426
|
+
ui.Flex,
|
|
5427
|
+
{
|
|
5428
|
+
align: "center",
|
|
5429
|
+
justify: "space-between",
|
|
5430
|
+
gap: 3,
|
|
5431
|
+
style: { flexWrap: "wrap", alignItems: "flex-start" },
|
|
5432
|
+
children: [
|
|
5433
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 240, flex: 1 }, children: [
|
|
5434
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: "Positioning mode" }),
|
|
5435
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 0, muted: !0, children: [
|
|
5436
|
+
"Choose between dragging on the canvas or manually editing the Mux",
|
|
5437
|
+
" ",
|
|
5438
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "overlay_settings" }),
|
|
5439
|
+
" fields (as in",
|
|
5440
|
+
" ",
|
|
5441
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5442
|
+
"a",
|
|
5443
|
+
{
|
|
5444
|
+
href: "https://www.mux.com/docs/guides/add-watermarks-to-your-videos",
|
|
5445
|
+
target: "_blank",
|
|
5446
|
+
rel: "noopener noreferrer",
|
|
5447
|
+
children: "the docs"
|
|
5448
|
+
}
|
|
5449
|
+
),
|
|
5450
|
+
")."
|
|
5451
|
+
] })
|
|
5452
|
+
] }),
|
|
5453
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, style: { flexWrap: "wrap" }, children: [
|
|
5454
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5455
|
+
ui.Button,
|
|
5456
|
+
{
|
|
5457
|
+
text: "Canvas",
|
|
5458
|
+
mode: mode === "canvas" ? "default" : "ghost",
|
|
5459
|
+
onClick: () => {
|
|
5460
|
+
setMode("canvas"), onChange({ ...watermark, enabled: !0, overlay_settings: void 0 });
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5463
|
+
),
|
|
5464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5465
|
+
ui.Button,
|
|
5466
|
+
{
|
|
5467
|
+
text: "Manual",
|
|
5468
|
+
mode: mode === "manual" ? "default" : "ghost",
|
|
5469
|
+
onClick: () => {
|
|
5470
|
+
setMode("manual");
|
|
5471
|
+
const overlay = convertWatermarkToMuxOverlay({ ...watermark, enabled: !0 });
|
|
5472
|
+
updateOverlaySettings(overlay ?? {});
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
)
|
|
5476
|
+
] })
|
|
5477
|
+
]
|
|
5478
|
+
}
|
|
5479
|
+
) }),
|
|
5480
|
+
mode === "manual" && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, tone: "transparent", border: !0, radius: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
5481
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: "Mux overlay_settings" }),
|
|
5482
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Grid, { columns: [1, 2], gap: 3, style: { width: "100%" }, children: [
|
|
5483
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5484
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "horizontal_align" }),
|
|
5485
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5486
|
+
"select",
|
|
5487
|
+
{
|
|
5488
|
+
value: watermark.overlay_settings?.horizontal_align || "right",
|
|
5489
|
+
onChange: (e) => updateOverlaySettings({
|
|
5490
|
+
horizontal_align: e.target.value || "right"
|
|
5491
|
+
}),
|
|
5492
|
+
style: {
|
|
5493
|
+
width: "100%",
|
|
5494
|
+
padding: "8px 10px",
|
|
5495
|
+
border: "1px solid #ccc",
|
|
5496
|
+
borderRadius: 4
|
|
5497
|
+
},
|
|
5498
|
+
children: [
|
|
5499
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "left", children: "left" }),
|
|
5500
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "center", children: "center" }),
|
|
5501
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "right", children: "right" })
|
|
5502
|
+
]
|
|
5503
|
+
}
|
|
5504
|
+
)
|
|
5505
|
+
] }),
|
|
5506
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5507
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "horizontal_margin (e.g. 2% or 40px)" }),
|
|
5508
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5509
|
+
ui.TextInput,
|
|
5510
|
+
{
|
|
5511
|
+
value: watermark.overlay_settings?.horizontal_margin || "2%",
|
|
5512
|
+
onChange: (e) => updateOverlaySettings({ horizontal_margin: e.currentTarget.value })
|
|
5513
|
+
}
|
|
5514
|
+
)
|
|
5515
|
+
] }),
|
|
5516
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5517
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "vertical_align" }),
|
|
5518
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5519
|
+
"select",
|
|
5520
|
+
{
|
|
5521
|
+
value: watermark.overlay_settings?.vertical_align || "bottom",
|
|
5522
|
+
onChange: (e) => updateOverlaySettings({
|
|
5523
|
+
vertical_align: e.target.value || "bottom"
|
|
5524
|
+
}),
|
|
5525
|
+
style: {
|
|
5526
|
+
width: "100%",
|
|
5527
|
+
padding: "8px 10px",
|
|
5528
|
+
border: "1px solid #ccc",
|
|
5529
|
+
borderRadius: 4
|
|
5530
|
+
},
|
|
5531
|
+
children: [
|
|
5532
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "top", children: "top" }),
|
|
5533
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "middle", children: "middle" }),
|
|
5534
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "bottom", children: "bottom" })
|
|
5535
|
+
]
|
|
5536
|
+
}
|
|
5537
|
+
)
|
|
5538
|
+
] }),
|
|
5539
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5540
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "vertical_margin (e.g. 2% or 40px)" }),
|
|
5541
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5542
|
+
ui.TextInput,
|
|
5543
|
+
{
|
|
5544
|
+
value: watermark.overlay_settings?.vertical_margin || "2%",
|
|
5545
|
+
onChange: (e) => updateOverlaySettings({ vertical_margin: e.currentTarget.value })
|
|
5546
|
+
}
|
|
5547
|
+
)
|
|
5548
|
+
] }),
|
|
5549
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5550
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "width (e.g. 25% or 80px)" }),
|
|
5551
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5552
|
+
ui.TextInput,
|
|
5553
|
+
{
|
|
5554
|
+
value: watermark.overlay_settings?.width || `${watermark.size ?? 20}%`,
|
|
5555
|
+
onChange: (e) => updateOverlaySettings({ width: e.currentTarget.value })
|
|
5556
|
+
}
|
|
5557
|
+
)
|
|
5558
|
+
] }),
|
|
5559
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, style: { minWidth: 0 }, children: [
|
|
5560
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "opacity (e.g. 90%)" }),
|
|
5561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5562
|
+
ui.TextInput,
|
|
5563
|
+
{
|
|
5564
|
+
value: watermark.overlay_settings?.opacity || `${Math.round((watermark.opacity ?? 0.7) * 100)}%`,
|
|
5565
|
+
onChange: (e) => updateOverlaySettings({ opacity: e.currentTarget.value })
|
|
5566
|
+
}
|
|
5567
|
+
)
|
|
5568
|
+
] })
|
|
5569
|
+
] }),
|
|
5570
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: "Margins and width accept either percentages or pixels, per the Mux guide." })
|
|
5571
|
+
] }) }),
|
|
5572
|
+
mode === "canvas" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5573
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { children: [
|
|
5574
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "medium", children: (() => {
|
|
5575
|
+
const sizePct = watermark.size || 20, contentW = getVideoContentBox().width;
|
|
5576
|
+
return contentW ? `Size: ${Math.max(1, Math.round(sizePct / 100 * contentW))}px` : `Size: ${sizePct}%`;
|
|
5577
|
+
})() }),
|
|
5578
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5579
|
+
RangeInput,
|
|
5580
|
+
{
|
|
5581
|
+
type: "range",
|
|
5582
|
+
value: (() => {
|
|
5583
|
+
const sizePct = watermark.size || 20, contentW = getVideoContentBox().width;
|
|
5584
|
+
return contentW ? Math.max(1, Math.round(sizePct / 100 * contentW)) : sizePct;
|
|
5585
|
+
})(),
|
|
5586
|
+
min: (() => {
|
|
5587
|
+
const contentW = getVideoContentBox().width;
|
|
5588
|
+
return contentW ? Math.max(1, Math.round(contentW * 0.05)) : 5;
|
|
5589
|
+
})(),
|
|
5590
|
+
max: (() => {
|
|
5591
|
+
const contentW = getVideoContentBox().width;
|
|
5592
|
+
return contentW ? Math.max(1, Math.round(contentW * 0.5)) : 50;
|
|
5593
|
+
})(),
|
|
5594
|
+
step: 1,
|
|
5595
|
+
onChange: (e) => {
|
|
5596
|
+
const raw = Number(e.target.value), contentW = getVideoContentBox().width, nextPct = contentW ? raw / contentW * 100 : raw, clampedPct = Math.max(5, Math.min(50, nextPct));
|
|
5597
|
+
onChange({
|
|
5598
|
+
...watermark,
|
|
5599
|
+
size: clampedPct
|
|
5600
|
+
});
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
)
|
|
5604
|
+
] }),
|
|
5605
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Box, { children: [
|
|
5606
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: 1, weight: "medium", children: [
|
|
5607
|
+
"Opacity: ",
|
|
5608
|
+
Math.round((watermark.opacity ?? 0.7) * 100),
|
|
5609
|
+
"%"
|
|
5610
|
+
] }),
|
|
5611
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5612
|
+
RangeInput,
|
|
5613
|
+
{
|
|
5614
|
+
type: "range",
|
|
5615
|
+
value: watermark.opacity ?? 0.7,
|
|
5616
|
+
min: 0,
|
|
5617
|
+
max: 1,
|
|
5618
|
+
step: 0.05,
|
|
5619
|
+
onChange: (e) => onChange({
|
|
5620
|
+
...watermark,
|
|
5621
|
+
opacity: Number(e.target.value)
|
|
5622
|
+
})
|
|
5623
|
+
}
|
|
5624
|
+
)
|
|
5625
|
+
] })
|
|
5626
|
+
] }),
|
|
5627
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 2, tone: "transparent", border: !0, radius: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 0, muted: !0, children: mode === "manual" ? "Manual mode: edit the overlay_settings fields above" : "\u{1F4A1} Drag the watermark on the preview to position it" }) })
|
|
5628
|
+
] })
|
|
5629
|
+
] });
|
|
5630
|
+
}
|
|
4995
5631
|
const ALL_LANGUAGE_CODES = LanguagesList__default.default.getAllCodes().map((code) => ({
|
|
4996
5632
|
value: code,
|
|
4997
5633
|
label: LanguagesList__default.default.getNativeName(code)
|
|
@@ -5433,7 +6069,7 @@ function UploadConfiguration({
|
|
|
5433
6069
|
startUpload,
|
|
5434
6070
|
onClose
|
|
5435
6071
|
}) {
|
|
5436
|
-
const id = React.useId(), autoTextTracks = React.useRef(
|
|
6072
|
+
const id = React.useId(), [watermarkValidationError, setWatermarkValidationError] = React.useState(null), watermarkPreviewContainerRef = React.useRef(null), watermarkPreviewVideoRef = React.useRef(null), autoTextTracks = React.useRef(
|
|
5437
6073
|
pluginConfig.video_quality === "plus" && pluginConfig.defaultAutogeneratedSubtitleLang ? [
|
|
5438
6074
|
{
|
|
5439
6075
|
_id: uuid.uuid(),
|
|
@@ -5469,6 +6105,8 @@ function UploadConfiguration({
|
|
|
5469
6105
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
5470
6106
|
case "drm_policy":
|
|
5471
6107
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
6108
|
+
case "watermark":
|
|
6109
|
+
return Object.assign({}, prev, { watermark: action.value });
|
|
5472
6110
|
// Updating individual tracks
|
|
5473
6111
|
case "track": {
|
|
5474
6112
|
const text_tracks = [...prev.text_tracks], target_track_i = text_tracks.findIndex(({ _id: _id2 }) => _id2 === action.id);
|
|
@@ -5536,7 +6174,12 @@ function UploadConfiguration({
|
|
|
5536
6174
|
]);
|
|
5537
6175
|
const { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
|
|
5538
6176
|
if (React.useEffect(() => {
|
|
5539
|
-
|
|
6177
|
+
if (skipConfig) {
|
|
6178
|
+
const { settings, watermark } = formatUploadConfig(config, secrets, {
|
|
6179
|
+
videoAspectRatio: videoAssetMetadata?.aspectRatio
|
|
6180
|
+
});
|
|
6181
|
+
startUpload(settings, watermark);
|
|
6182
|
+
}
|
|
5540
6183
|
}, []), skipConfig) return null;
|
|
5541
6184
|
const basicConfig = config.video_quality !== "plus" && config.video_quality !== "premium", playbackPolicySelected = config.public_policy || config.signed_policy || config.drm_policy, maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
5542
6185
|
(rt) => rt.value === pluginConfig.max_resolution_tier
|
|
@@ -5552,11 +6195,11 @@ function UploadConfiguration({
|
|
|
5552
6195
|
header: "Configure Mux Upload",
|
|
5553
6196
|
onClose,
|
|
5554
6197
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { padding: 4, space: 2, children: [
|
|
5555
|
-
validationError && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, tone: "critical", radius: 2, marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, align: "flex-start", children: [
|
|
6198
|
+
(validationError || watermarkValidationError) && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, tone: "critical", radius: 2, marginBottom: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 2, align: "flex-start", children: [
|
|
5556
6199
|
/* @__PURE__ */ jsxRuntime.jsx(icons.ErrorOutlineIcon, { width: 20, height: 20 }),
|
|
5557
6200
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
5558
6201
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, weight: "semibold", children: "Validation Error" }),
|
|
5559
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: validationError })
|
|
6202
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: validationError || watermarkValidationError })
|
|
5560
6203
|
] })
|
|
5561
6204
|
] }) }),
|
|
5562
6205
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 3, children: "FILE TO UPLOAD" }),
|
|
@@ -5623,27 +6266,41 @@ function UploadConfiguration({
|
|
|
5623
6266
|
}) })
|
|
5624
6267
|
}
|
|
5625
6268
|
),
|
|
5626
|
-
!basicConfig && /* @__PURE__ */ jsxRuntime.
|
|
5627
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5628
|
-
|
|
5629
|
-
|
|
6269
|
+
!basicConfig && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6270
|
+
/* @__PURE__ */ jsxRuntime.jsx(sanity.FormField, { title: "Additional Configuration", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
6271
|
+
/* @__PURE__ */ jsxRuntime.jsx(PlaybackPolicy, { id, config, secrets, dispatch }),
|
|
6272
|
+
maxSupportedResolution > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6273
|
+
ResolutionTierSelector,
|
|
6274
|
+
{
|
|
6275
|
+
id,
|
|
6276
|
+
config,
|
|
6277
|
+
dispatch,
|
|
6278
|
+
maxSupportedResolution
|
|
6279
|
+
}
|
|
6280
|
+
),
|
|
6281
|
+
/* @__PURE__ */ jsxRuntime.jsx(StaticRenditionSelector, { id, config, dispatch }),
|
|
6282
|
+
!disableTextTrackConfig && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6283
|
+
TextTracksEditor,
|
|
6284
|
+
{
|
|
6285
|
+
tracks: config.text_tracks,
|
|
6286
|
+
dispatch,
|
|
6287
|
+
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
6288
|
+
}
|
|
6289
|
+
)
|
|
6290
|
+
] }) }),
|
|
6291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6292
|
+
WatermarkSection,
|
|
5630
6293
|
{
|
|
5631
|
-
id,
|
|
5632
6294
|
config,
|
|
5633
6295
|
dispatch,
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
TextTracksEditor,
|
|
5640
|
-
{
|
|
5641
|
-
tracks: config.text_tracks,
|
|
5642
|
-
dispatch,
|
|
5643
|
-
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
6296
|
+
stagedUpload,
|
|
6297
|
+
videoAssetMetadata,
|
|
6298
|
+
watermarkPreviewContainerRef,
|
|
6299
|
+
watermarkPreviewVideoRef,
|
|
6300
|
+
onValidationChange: setWatermarkValidationError
|
|
5644
6301
|
}
|
|
5645
6302
|
)
|
|
5646
|
-
] })
|
|
6303
|
+
] })
|
|
5647
6304
|
] }),
|
|
5648
6305
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5649
6306
|
ui.Button,
|
|
@@ -5653,7 +6310,12 @@ function UploadConfiguration({
|
|
|
5653
6310
|
text: "Upload",
|
|
5654
6311
|
tone: "positive",
|
|
5655
6312
|
onClick: () => {
|
|
5656
|
-
|
|
6313
|
+
if (!validationError) {
|
|
6314
|
+
const { settings, watermark } = formatUploadConfig(config, secrets, {
|
|
6315
|
+
videoAspectRatio: videoAssetMetadata?.aspectRatio
|
|
6316
|
+
});
|
|
6317
|
+
startUpload(settings, watermark);
|
|
6318
|
+
}
|
|
5657
6319
|
}
|
|
5658
6320
|
}
|
|
5659
6321
|
) })
|
|
@@ -5668,36 +6330,178 @@ function setAdvancedPlaybackPolicy(config, secrets) {
|
|
|
5668
6330
|
drm_configuration_id: secrets.drmConfigId ?? void 0
|
|
5669
6331
|
}) : console.error("Selected DRM Policy but missing DRM Configuration Id")), advanced_playback_policies;
|
|
5670
6332
|
}
|
|
5671
|
-
function formatUploadConfig(config, secrets) {
|
|
6333
|
+
function formatUploadConfig(config, secrets, options) {
|
|
5672
6334
|
const generated_subtitles = config.text_tracks.filter(isAutogeneratedTrack).map((track) => ({
|
|
5673
6335
|
name: track.name,
|
|
5674
6336
|
language_code: track.language_code
|
|
5675
|
-
}))
|
|
6337
|
+
})), inputs = [
|
|
6338
|
+
{
|
|
6339
|
+
type: "video",
|
|
6340
|
+
generated_subtitles: generated_subtitles.length > 0 ? generated_subtitles : void 0
|
|
6341
|
+
},
|
|
6342
|
+
...config.text_tracks.filter(isCustomTextTrack).reduce(
|
|
6343
|
+
(acc, track) => (track.language_code && track.file && track.name && acc.push({
|
|
6344
|
+
url: track.file.contents,
|
|
6345
|
+
type: "text",
|
|
6346
|
+
text_type: track.type === "subtitles" ? "subtitles" : void 0,
|
|
6347
|
+
language_code: track.language_code,
|
|
6348
|
+
name: track.name,
|
|
6349
|
+
closed_captions: track.type === "captions"
|
|
6350
|
+
}), acc),
|
|
6351
|
+
[]
|
|
6352
|
+
)
|
|
6353
|
+
];
|
|
6354
|
+
if (config.watermark?.imageUrl) {
|
|
6355
|
+
const watermarkForMux = { ...config.watermark, enabled: !0 }, overlaySettings = convertWatermarkToMuxOverlay(watermarkForMux, {
|
|
6356
|
+
videoAspectRatio: options?.videoAspectRatio ?? void 0,
|
|
6357
|
+
units: "px"
|
|
6358
|
+
});
|
|
6359
|
+
overlaySettings && inputs.push({
|
|
6360
|
+
url: config.watermark.imageUrl,
|
|
6361
|
+
overlay_settings: overlaySettings
|
|
6362
|
+
});
|
|
6363
|
+
}
|
|
5676
6364
|
return {
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
text_type: track.type === "subtitles" ? "subtitles" : void 0,
|
|
5687
|
-
language_code: track.language_code,
|
|
5688
|
-
name: track.name,
|
|
5689
|
-
closed_captions: track.type === "captions"
|
|
5690
|
-
}), acc),
|
|
5691
|
-
[]
|
|
5692
|
-
)
|
|
5693
|
-
],
|
|
5694
|
-
static_renditions: config.static_renditions.length > 0 ? config.static_renditions.map((resolution) => ({ resolution })) : void 0,
|
|
5695
|
-
advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),
|
|
5696
|
-
max_resolution_tier: config.max_resolution_tier,
|
|
5697
|
-
video_quality: config.video_quality,
|
|
5698
|
-
normalize_audio: config.normalize_audio
|
|
6365
|
+
settings: {
|
|
6366
|
+
input: inputs,
|
|
6367
|
+
static_renditions: config.static_renditions.length > 0 ? config.static_renditions.map((resolution) => ({ resolution })) : void 0,
|
|
6368
|
+
advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),
|
|
6369
|
+
max_resolution_tier: config.max_resolution_tier,
|
|
6370
|
+
video_quality: config.video_quality,
|
|
6371
|
+
normalize_audio: config.normalize_audio
|
|
6372
|
+
},
|
|
6373
|
+
watermark: config.watermark?.imageUrl ? { ...config.watermark, enabled: !0 } : void 0
|
|
5699
6374
|
};
|
|
5700
6375
|
}
|
|
6376
|
+
function WatermarkSection({
|
|
6377
|
+
config,
|
|
6378
|
+
dispatch,
|
|
6379
|
+
stagedUpload,
|
|
6380
|
+
videoAssetMetadata,
|
|
6381
|
+
watermarkPreviewContainerRef,
|
|
6382
|
+
watermarkPreviewVideoRef,
|
|
6383
|
+
onValidationChange
|
|
6384
|
+
}) {
|
|
6385
|
+
return videoAssetMetadata?.isAudioOnly !== !1 ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
6386
|
+
sanity.FormField,
|
|
6387
|
+
{
|
|
6388
|
+
title: "Watermark",
|
|
6389
|
+
description: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6390
|
+
"Add a watermark overlay to your video using Mux's native watermark support.",
|
|
6391
|
+
" ",
|
|
6392
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6393
|
+
"a",
|
|
6394
|
+
{
|
|
6395
|
+
href: "https://www.mux.com/docs/guides/add-watermarks-to-your-videos",
|
|
6396
|
+
target: "_blank",
|
|
6397
|
+
rel: "noopener noreferrer",
|
|
6398
|
+
children: "Learn more about Mux watermarks."
|
|
6399
|
+
}
|
|
6400
|
+
)
|
|
6401
|
+
] }),
|
|
6402
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
6403
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6404
|
+
WatermarkControls,
|
|
6405
|
+
{
|
|
6406
|
+
watermark: config.watermark || { enabled: !1 },
|
|
6407
|
+
onChange: (watermark) => {
|
|
6408
|
+
dispatch({ action: "watermark", value: watermark });
|
|
6409
|
+
},
|
|
6410
|
+
onValidationChange,
|
|
6411
|
+
previewContainerRef: watermarkPreviewContainerRef,
|
|
6412
|
+
previewVideoRef: watermarkPreviewVideoRef
|
|
6413
|
+
}
|
|
6414
|
+
),
|
|
6415
|
+
config.watermark?.imageUrl && stagedUpload.type === "file" && // Canvas preview is only shown in "Canvas" mode (no explicit overlay_settings)
|
|
6416
|
+
!config.watermark.overlay_settings && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6417
|
+
WatermarkPreview,
|
|
6418
|
+
{
|
|
6419
|
+
stagedUpload,
|
|
6420
|
+
watermark: config.watermark,
|
|
6421
|
+
videoAspectRatio: videoAssetMetadata.aspectRatio,
|
|
6422
|
+
onWatermarkChange: (watermark) => {
|
|
6423
|
+
dispatch({ action: "watermark", value: watermark });
|
|
6424
|
+
},
|
|
6425
|
+
previewContainerRef: watermarkPreviewContainerRef,
|
|
6426
|
+
videoRef: watermarkPreviewVideoRef
|
|
6427
|
+
}
|
|
6428
|
+
)
|
|
6429
|
+
] })
|
|
6430
|
+
}
|
|
6431
|
+
);
|
|
6432
|
+
}
|
|
6433
|
+
const WatermarkPreview = React.memo(function({
|
|
6434
|
+
stagedUpload,
|
|
6435
|
+
watermark,
|
|
6436
|
+
onWatermarkChange,
|
|
6437
|
+
videoAspectRatio,
|
|
6438
|
+
previewContainerRef,
|
|
6439
|
+
videoRef
|
|
6440
|
+
}) {
|
|
6441
|
+
React.useEffect(() => {
|
|
6442
|
+
if (videoRef.current && stagedUpload.type === "file") {
|
|
6443
|
+
const file = stagedUpload.files[0], url = URL.createObjectURL(file);
|
|
6444
|
+
return videoRef.current.src = url, () => {
|
|
6445
|
+
URL.revokeObjectURL(url);
|
|
6446
|
+
};
|
|
6447
|
+
}
|
|
6448
|
+
}, [stagedUpload, videoRef]);
|
|
6449
|
+
const isVertical = videoAspectRatio != null && videoAspectRatio < 1;
|
|
6450
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6451
|
+
ui.Card,
|
|
6452
|
+
{
|
|
6453
|
+
tone: "transparent",
|
|
6454
|
+
border: !0,
|
|
6455
|
+
style: {
|
|
6456
|
+
overflow: "hidden",
|
|
6457
|
+
// For vertical videos, center the preview and limit its width
|
|
6458
|
+
display: "flex",
|
|
6459
|
+
justifyContent: "center"
|
|
6460
|
+
},
|
|
6461
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6462
|
+
"div",
|
|
6463
|
+
{
|
|
6464
|
+
ref: previewContainerRef,
|
|
6465
|
+
style: {
|
|
6466
|
+
position: "relative",
|
|
6467
|
+
// For vertical videos: limit width so the preview doesn't get too tall
|
|
6468
|
+
// For horizontal videos: use full width
|
|
6469
|
+
width: isVertical ? "auto" : "100%",
|
|
6470
|
+
aspectRatio: videoAspectRatio ? String(videoAspectRatio) : "16/9",
|
|
6471
|
+
...isVertical ? { height: "400px", maxHeight: "50vh" } : { minHeight: "200px" },
|
|
6472
|
+
overflow: "hidden"
|
|
6473
|
+
},
|
|
6474
|
+
children: [
|
|
6475
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6476
|
+
"video",
|
|
6477
|
+
{
|
|
6478
|
+
ref: videoRef,
|
|
6479
|
+
style: {
|
|
6480
|
+
position: "absolute",
|
|
6481
|
+
top: 0,
|
|
6482
|
+
left: 0,
|
|
6483
|
+
width: "100%",
|
|
6484
|
+
height: "100%",
|
|
6485
|
+
objectFit: "fill",
|
|
6486
|
+
display: "block"
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
),
|
|
6490
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6491
|
+
DraggableWatermark,
|
|
6492
|
+
{
|
|
6493
|
+
watermark,
|
|
6494
|
+
onChange: onWatermarkChange,
|
|
6495
|
+
containerRef: previewContainerRef,
|
|
6496
|
+
videoElementRef: videoRef
|
|
6497
|
+
}
|
|
6498
|
+
)
|
|
6499
|
+
]
|
|
6500
|
+
}
|
|
6501
|
+
)
|
|
6502
|
+
}
|
|
6503
|
+
);
|
|
6504
|
+
});
|
|
5701
6505
|
function withFocusRing(component) {
|
|
5702
6506
|
return styledComponents.styled(component)((props) => {
|
|
5703
6507
|
const border = {
|
|
@@ -5936,7 +6740,7 @@ function Uploader(props) {
|
|
|
5936
6740
|
window.removeEventListener("beforeunload", handleBeforeUnload), window.removeEventListener("pagehide", handleBeforeUnload), cleanup();
|
|
5937
6741
|
};
|
|
5938
6742
|
}, [props.client, props.asset?._id]);
|
|
5939
|
-
const startUpload = (settings) => {
|
|
6743
|
+
const startUpload = (settings, watermark) => {
|
|
5940
6744
|
const { stagedUpload } = state;
|
|
5941
6745
|
if (!stagedUpload || uploadRef.current) return;
|
|
5942
6746
|
dispatch({ action: "commitUpload" });
|
|
@@ -5946,14 +6750,16 @@ function Uploader(props) {
|
|
|
5946
6750
|
uploadObservable = uploadUrl({
|
|
5947
6751
|
client: props.client,
|
|
5948
6752
|
url: stagedUpload.url,
|
|
5949
|
-
settings
|
|
6753
|
+
settings,
|
|
6754
|
+
watermark
|
|
5950
6755
|
});
|
|
5951
6756
|
break;
|
|
5952
6757
|
case "file":
|
|
5953
6758
|
uploadObservable = uploadFile({
|
|
5954
6759
|
client: props.client,
|
|
5955
6760
|
file: stagedUpload.files[0],
|
|
5956
|
-
settings
|
|
6761
|
+
settings,
|
|
6762
|
+
watermark
|
|
5957
6763
|
}).pipe(
|
|
5958
6764
|
operators.takeUntil(
|
|
5959
6765
|
cancelUploadButton.observable.pipe(
|