@twick/studio 0.15.19 → 0.15.20
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 +25 -0
- package/dist/components/container/element-panel-container.d.ts +3 -2
- package/dist/components/container/generate-media-panel-container.d.ts +13 -0
- package/dist/components/properties/caption-prop.d.ts +6 -21
- package/dist/helpers/constant.d.ts +36 -0
- package/dist/hooks/use-generate-image.d.ts +10 -0
- package/dist/hooks/use-generate-video.d.ts +10 -0
- package/dist/index.js +682 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +685 -26
- package/dist/index.mjs.map +1 -1
- package/dist/types/generation.d.ts +44 -0
- package/dist/types/index.d.ts +5 -0
- package/package.json +13 -12
package/dist/index.mjs
CHANGED
|
@@ -3,8 +3,8 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
5
5
|
import { forwardRef, createElement, useState, useEffect, useRef, useCallback, createContext, useContext, useMemo } from "react";
|
|
6
|
-
import { useTimelineContext, TrackElement, Track, ImageElement, AudioElement, VideoElement, TextElement, RectElement, CircleElement, CAPTION_STYLE, CaptionElement, ElementTextEffect, ElementAnimation, PLAYER_STATE } from "@twick/timeline";
|
|
7
|
-
import { AudioElement as AudioElement2, CAPTION_COLOR, CAPTION_FONT, CAPTION_STYLE as CAPTION_STYLE2, CAPTION_STYLE_OPTIONS, CaptionElement as CaptionElement2, CircleElement as CircleElement2, ElementAdder, ElementAnimation as ElementAnimation2, ElementCloner, ElementDeserializer, ElementFrameEffect, ElementRemover, ElementSerializer, ElementSplitter, ElementTextEffect as ElementTextEffect2, ElementUpdater, ElementValidator, INITIAL_TIMELINE_DATA, IconElement, ImageElement as ImageElement2, PROCESS_STATE, RectElement as RectElement2, TIMELINE_ACTION, TIMELINE_ELEMENT_TYPE, TextElement as TextElement2, TimelineEditor, TimelineProvider, Track as Track2, TrackElement as TrackElement2, VideoElement as VideoElement2, WORDS_PER_PHRASE, generateShortUuid, getCurrentElements, getTotalDuration, isElementId, isTrackId, useTimelineContext as useTimelineContext2 } from "@twick/timeline";
|
|
6
|
+
import { useTimelineContext, TrackElement, Track, ImageElement, AudioElement, VideoElement, TextElement, RectElement, CircleElement, CAPTION_STYLE, CaptionElement, ElementTextEffect, ElementAnimation, CAPTION_STYLE_OPTIONS, PLAYER_STATE } from "@twick/timeline";
|
|
7
|
+
import { AudioElement as AudioElement2, CAPTION_COLOR, CAPTION_FONT, CAPTION_STYLE as CAPTION_STYLE2, CAPTION_STYLE_OPTIONS as CAPTION_STYLE_OPTIONS2, CaptionElement as CaptionElement2, CircleElement as CircleElement2, ElementAdder, ElementAnimation as ElementAnimation2, ElementCloner, ElementDeserializer, ElementFrameEffect, ElementRemover, ElementSerializer, ElementSplitter, ElementTextEffect as ElementTextEffect2, ElementUpdater, ElementValidator, INITIAL_TIMELINE_DATA, IconElement, ImageElement as ImageElement2, PROCESS_STATE, RectElement as RectElement2, TIMELINE_ACTION, TIMELINE_ELEMENT_TYPE, TextElement as TextElement2, TimelineEditor, TimelineProvider, Track as Track2, TrackElement as TrackElement2, VideoElement as VideoElement2, WORDS_PER_PHRASE, generateShortUuid, getCurrentElements, getTotalDuration, isElementId, isTrackId, useTimelineContext as useTimelineContext2 } from "@twick/timeline";
|
|
8
8
|
import VideoEditor, { useEditorManager, BrowserMediaManager, TIMELINE_DROP_MEDIA_TYPE, AVAILABLE_TEXT_FONTS, TEXT_EFFECTS, ANIMATIONS } from "@twick/video-editor";
|
|
9
9
|
import { ANIMATIONS as ANIMATIONS2, BaseMediaManager, BrowserMediaManager as BrowserMediaManager2, PlayerControls, TEXT_EFFECTS as TEXT_EFFECTS2, TimelineManager, default as default2, animationGifs, getAnimationGif, setElementColors, useEditorManager as useEditorManager2, usePlayerControl, useTimelineControl } from "@twick/video-editor";
|
|
10
10
|
import { useLivePlayerContext } from "@twick/live-player";
|
|
@@ -561,7 +561,8 @@ const toolCategories = [
|
|
|
561
561
|
{ id: "text", name: "Text", icon: "Type", description: "Add text elements" },
|
|
562
562
|
{ id: "circle", name: "Circle", icon: "Circle", description: "Add a circle element" },
|
|
563
563
|
{ id: "rect", name: "Rect", icon: "Rect", description: "Add a rectangle element" },
|
|
564
|
-
{ id: "caption", name: "Caption", icon: "MessageSquare", description: "Manage captions" }
|
|
564
|
+
{ id: "caption", name: "Caption", icon: "MessageSquare", description: "Manage captions" },
|
|
565
|
+
{ id: "generate-media", name: "Generate", icon: "Wand2", description: "Generate image or video with AI" }
|
|
565
566
|
];
|
|
566
567
|
const getIcon = (iconName) => {
|
|
567
568
|
switch (iconName) {
|
|
@@ -585,6 +586,8 @@ const getIcon = (iconName) => {
|
|
|
585
586
|
return Square;
|
|
586
587
|
case "MessageSquare":
|
|
587
588
|
return MessageSquare;
|
|
589
|
+
case "Wand2":
|
|
590
|
+
return WandSparkles;
|
|
588
591
|
default:
|
|
589
592
|
return Plus;
|
|
590
593
|
}
|
|
@@ -2829,6 +2832,42 @@ const CAPTION_PROPS = {
|
|
|
2829
2832
|
shadowOffset: [-2, 2],
|
|
2830
2833
|
shadowColor: "#000000",
|
|
2831
2834
|
shadowBlur: 5
|
|
2835
|
+
},
|
|
2836
|
+
[CAPTION_STYLE.OUTLINE_ONLY]: {
|
|
2837
|
+
font: {
|
|
2838
|
+
size: 42,
|
|
2839
|
+
weight: 600,
|
|
2840
|
+
family: "Arial"
|
|
2841
|
+
},
|
|
2842
|
+
colors: {
|
|
2843
|
+
text: "#ffffff",
|
|
2844
|
+
highlight: "#ff4081",
|
|
2845
|
+
bgColor: "#000000"
|
|
2846
|
+
},
|
|
2847
|
+
lineWidth: 0.5,
|
|
2848
|
+
stroke: "#000000",
|
|
2849
|
+
fontWeight: 600,
|
|
2850
|
+
shadowOffset: [0, 0],
|
|
2851
|
+
shadowColor: "#000000",
|
|
2852
|
+
shadowBlur: 0
|
|
2853
|
+
},
|
|
2854
|
+
[CAPTION_STYLE.SOFT_BOX]: {
|
|
2855
|
+
font: {
|
|
2856
|
+
size: 40,
|
|
2857
|
+
weight: 600,
|
|
2858
|
+
family: "Montserrat"
|
|
2859
|
+
},
|
|
2860
|
+
colors: {
|
|
2861
|
+
text: "#ffffff",
|
|
2862
|
+
highlight: "#ff4081",
|
|
2863
|
+
bgColor: "#333333"
|
|
2864
|
+
},
|
|
2865
|
+
lineWidth: 0.2,
|
|
2866
|
+
stroke: "#000000",
|
|
2867
|
+
fontWeight: 600,
|
|
2868
|
+
shadowOffset: [-1, 1],
|
|
2869
|
+
shadowColor: "rgba(0,0,0,0.3)",
|
|
2870
|
+
shadowBlur: 3
|
|
2832
2871
|
}
|
|
2833
2872
|
};
|
|
2834
2873
|
const useCaptionsPanel = () => {
|
|
@@ -2918,13 +2957,324 @@ function CaptionsPanelContainer() {
|
|
|
2918
2957
|
const captionsPanelProps = useCaptionsPanel();
|
|
2919
2958
|
return /* @__PURE__ */ jsx(CaptionsPanel, { ...captionsPanelProps });
|
|
2920
2959
|
}
|
|
2960
|
+
const FAL_IMAGE_ENDPOINTS = [
|
|
2961
|
+
{
|
|
2962
|
+
provider: "fal",
|
|
2963
|
+
endpointId: "fal-ai/flux-pro/kontext",
|
|
2964
|
+
label: "FLUX.1 Kontext [pro]",
|
|
2965
|
+
description: "Professional image generation with context-aware editing",
|
|
2966
|
+
popularity: 5,
|
|
2967
|
+
category: "image",
|
|
2968
|
+
inputAsset: ["image"],
|
|
2969
|
+
availableDimensions: [
|
|
2970
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
2971
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
2972
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
2973
|
+
]
|
|
2974
|
+
},
|
|
2975
|
+
{
|
|
2976
|
+
provider: "fal",
|
|
2977
|
+
endpointId: "fal-ai/flux/dev",
|
|
2978
|
+
label: "FLUX.1 [dev]",
|
|
2979
|
+
description: "High-quality image generation",
|
|
2980
|
+
popularity: 5,
|
|
2981
|
+
category: "image",
|
|
2982
|
+
minSteps: 1,
|
|
2983
|
+
maxSteps: 50,
|
|
2984
|
+
defaultSteps: 28,
|
|
2985
|
+
minGuidanceScale: 1,
|
|
2986
|
+
maxGuidanceScale: 20,
|
|
2987
|
+
defaultGuidanceScale: 3.5,
|
|
2988
|
+
hasSeed: true
|
|
2989
|
+
},
|
|
2990
|
+
{
|
|
2991
|
+
provider: "fal",
|
|
2992
|
+
endpointId: "fal-ai/flux/schnell",
|
|
2993
|
+
label: "FLUX.1 [schnell]",
|
|
2994
|
+
description: "Ultra-fast image generation",
|
|
2995
|
+
popularity: 4,
|
|
2996
|
+
category: "image",
|
|
2997
|
+
defaultSteps: 4,
|
|
2998
|
+
availableDimensions: [
|
|
2999
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
3000
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3001
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
3002
|
+
]
|
|
3003
|
+
},
|
|
3004
|
+
{
|
|
3005
|
+
provider: "fal",
|
|
3006
|
+
endpointId: "fal-ai/gemini-25-flash-image",
|
|
3007
|
+
label: "Gemini 2.5 Flash Image",
|
|
3008
|
+
description: "Rapid text-to-image generation",
|
|
3009
|
+
popularity: 5,
|
|
3010
|
+
category: "image",
|
|
3011
|
+
availableDimensions: [
|
|
3012
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" },
|
|
3013
|
+
{ width: 1024, height: 768, label: "1024x768 (4:3)" },
|
|
3014
|
+
{ width: 768, height: 1024, label: "768x1024 (3:4)" },
|
|
3015
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3016
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" }
|
|
3017
|
+
]
|
|
3018
|
+
},
|
|
3019
|
+
{
|
|
3020
|
+
provider: "fal",
|
|
3021
|
+
endpointId: "fal-ai/ideogram/v3",
|
|
3022
|
+
label: "Ideogram V3",
|
|
3023
|
+
description: "Advanced text-to-image with superior text rendering",
|
|
3024
|
+
popularity: 5,
|
|
3025
|
+
category: "image",
|
|
3026
|
+
hasSeed: true,
|
|
3027
|
+
hasNegativePrompt: true
|
|
3028
|
+
}
|
|
3029
|
+
];
|
|
3030
|
+
const FAL_VIDEO_ENDPOINTS = [
|
|
3031
|
+
{
|
|
3032
|
+
provider: "fal",
|
|
3033
|
+
endpointId: "fal-ai/veo3",
|
|
3034
|
+
label: "Veo 3",
|
|
3035
|
+
description: "Google Veo 3 text-to-video",
|
|
3036
|
+
popularity: 5,
|
|
3037
|
+
category: "video",
|
|
3038
|
+
availableDurations: [4, 6, 8],
|
|
3039
|
+
defaultDuration: 8,
|
|
3040
|
+
availableDimensions: [
|
|
3041
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3042
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3043
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3044
|
+
]
|
|
3045
|
+
},
|
|
3046
|
+
{
|
|
3047
|
+
provider: "fal",
|
|
3048
|
+
endpointId: "fal-ai/veo3/fast",
|
|
3049
|
+
label: "Veo 3 Fast",
|
|
3050
|
+
description: "Accelerated Veo 3 text-to-video",
|
|
3051
|
+
popularity: 5,
|
|
3052
|
+
category: "video",
|
|
3053
|
+
availableDurations: [4, 6, 8],
|
|
3054
|
+
defaultDuration: 8,
|
|
3055
|
+
availableDimensions: [
|
|
3056
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3057
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3058
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3059
|
+
]
|
|
3060
|
+
},
|
|
3061
|
+
{
|
|
3062
|
+
provider: "fal",
|
|
3063
|
+
endpointId: "fal-ai/veo3/image-to-video",
|
|
3064
|
+
label: "Veo 3 Image-to-Video",
|
|
3065
|
+
description: "Animate images with Veo 3",
|
|
3066
|
+
popularity: 5,
|
|
3067
|
+
category: "video",
|
|
3068
|
+
inputAsset: ["image"],
|
|
3069
|
+
availableDurations: [8],
|
|
3070
|
+
defaultDuration: 8
|
|
3071
|
+
},
|
|
3072
|
+
{
|
|
3073
|
+
provider: "fal",
|
|
3074
|
+
endpointId: "fal-ai/kling-video/v2.5-turbo/pro/text-to-video",
|
|
3075
|
+
label: "Kling 2.5 Turbo Pro",
|
|
3076
|
+
description: "Text-to-video with fluid motion",
|
|
3077
|
+
popularity: 5,
|
|
3078
|
+
category: "video",
|
|
3079
|
+
availableDurations: [5, 10],
|
|
3080
|
+
defaultDuration: 5,
|
|
3081
|
+
availableDimensions: [
|
|
3082
|
+
{ width: 1024, height: 576, label: "1024x576 (16:9)" },
|
|
3083
|
+
{ width: 576, height: 1024, label: "576x1024 (9:16)" },
|
|
3084
|
+
{ width: 1024, height: 1024, label: "1024x1024 (1:1)" }
|
|
3085
|
+
]
|
|
3086
|
+
}
|
|
3087
|
+
];
|
|
3088
|
+
const DEFAULT_IMAGE_DURATION = 5;
|
|
3089
|
+
function GenerateMediaPanelContainer({
|
|
3090
|
+
videoResolution,
|
|
3091
|
+
addElement,
|
|
3092
|
+
studioConfig
|
|
3093
|
+
}) {
|
|
3094
|
+
var _a;
|
|
3095
|
+
const { getCurrentTime } = useLivePlayerContext();
|
|
3096
|
+
const [tab, setTab] = useState("image");
|
|
3097
|
+
const [prompt2, setPrompt] = useState("");
|
|
3098
|
+
const [selectedEndpointId, setSelectedEndpointId] = useState("");
|
|
3099
|
+
const [isGenerating, setIsGenerating] = useState(false);
|
|
3100
|
+
const [error, setError] = useState(null);
|
|
3101
|
+
const [status, setStatus] = useState(null);
|
|
3102
|
+
const imageService = studioConfig == null ? void 0 : studioConfig.imageGenerationService;
|
|
3103
|
+
const videoService = studioConfig == null ? void 0 : studioConfig.videoGenerationService;
|
|
3104
|
+
const hasAnyService = !!imageService || !!videoService;
|
|
3105
|
+
const endpoints = tab === "image" ? FAL_IMAGE_ENDPOINTS : FAL_VIDEO_ENDPOINTS;
|
|
3106
|
+
const defaultEndpointId = ((_a = endpoints[0]) == null ? void 0 : _a.endpointId) ?? "";
|
|
3107
|
+
useEffect(() => {
|
|
3108
|
+
if (!selectedEndpointId && defaultEndpointId) {
|
|
3109
|
+
setSelectedEndpointId(defaultEndpointId);
|
|
3110
|
+
}
|
|
3111
|
+
}, [tab, defaultEndpointId, selectedEndpointId]);
|
|
3112
|
+
const pollStatus = useCallback(
|
|
3113
|
+
async (requestId) => {
|
|
3114
|
+
const service = tab === "image" ? imageService : videoService;
|
|
3115
|
+
if (!service) return;
|
|
3116
|
+
const interval = setInterval(async () => {
|
|
3117
|
+
try {
|
|
3118
|
+
const result = await service.getRequestStatus(requestId);
|
|
3119
|
+
if (result.status === "completed" && result.url) {
|
|
3120
|
+
clearInterval(interval);
|
|
3121
|
+
setIsGenerating(false);
|
|
3122
|
+
setStatus(null);
|
|
3123
|
+
setError(null);
|
|
3124
|
+
const currentTime = getCurrentTime();
|
|
3125
|
+
const duration = result.duration ?? DEFAULT_IMAGE_DURATION;
|
|
3126
|
+
if (tab === "image") {
|
|
3127
|
+
const element = new ImageElement(result.url, videoResolution);
|
|
3128
|
+
element.setStart(currentTime);
|
|
3129
|
+
element.setEnd(currentTime + duration);
|
|
3130
|
+
addElement(element);
|
|
3131
|
+
} else {
|
|
3132
|
+
const element = new VideoElement(result.url, videoResolution);
|
|
3133
|
+
element.setStart(currentTime);
|
|
3134
|
+
element.setEnd(currentTime + duration);
|
|
3135
|
+
addElement(element);
|
|
3136
|
+
}
|
|
3137
|
+
} else if (result.status === "failed") {
|
|
3138
|
+
clearInterval(interval);
|
|
3139
|
+
setIsGenerating(false);
|
|
3140
|
+
setStatus(null);
|
|
3141
|
+
setError(result.error ?? "Generation failed");
|
|
3142
|
+
}
|
|
3143
|
+
} catch {
|
|
3144
|
+
}
|
|
3145
|
+
}, 3e3);
|
|
3146
|
+
return () => clearInterval(interval);
|
|
3147
|
+
},
|
|
3148
|
+
[tab, imageService, videoService, getCurrentTime, videoResolution, addElement]
|
|
3149
|
+
);
|
|
3150
|
+
const handleGenerate = useCallback(async () => {
|
|
3151
|
+
if (!prompt2.trim()) {
|
|
3152
|
+
setError("Enter a prompt");
|
|
3153
|
+
return;
|
|
3154
|
+
}
|
|
3155
|
+
if (tab === "image" && !imageService) {
|
|
3156
|
+
setError("Image generation not configured");
|
|
3157
|
+
return;
|
|
3158
|
+
}
|
|
3159
|
+
if (tab === "video" && !videoService) {
|
|
3160
|
+
setError("Video generation not configured");
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
setIsGenerating(true);
|
|
3164
|
+
setError(null);
|
|
3165
|
+
setStatus("Starting...");
|
|
3166
|
+
try {
|
|
3167
|
+
const endpointId = selectedEndpointId || defaultEndpointId;
|
|
3168
|
+
if (tab === "image" && imageService) {
|
|
3169
|
+
const requestId = await imageService.generateImage({
|
|
3170
|
+
provider: "fal",
|
|
3171
|
+
endpointId,
|
|
3172
|
+
prompt: prompt2.trim()
|
|
3173
|
+
});
|
|
3174
|
+
if (requestId) {
|
|
3175
|
+
setStatus("Generating image...");
|
|
3176
|
+
pollStatus(requestId);
|
|
3177
|
+
}
|
|
3178
|
+
} else if (tab === "video" && videoService) {
|
|
3179
|
+
const requestId = await videoService.generateVideo({
|
|
3180
|
+
provider: "fal",
|
|
3181
|
+
endpointId,
|
|
3182
|
+
prompt: prompt2.trim()
|
|
3183
|
+
});
|
|
3184
|
+
if (requestId) {
|
|
3185
|
+
setStatus("Generating video (this may take several minutes)...");
|
|
3186
|
+
pollStatus(requestId);
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
} catch (err) {
|
|
3190
|
+
const msg = err instanceof Error ? err.message : "Generation failed";
|
|
3191
|
+
setError(msg);
|
|
3192
|
+
setIsGenerating(false);
|
|
3193
|
+
setStatus(null);
|
|
3194
|
+
}
|
|
3195
|
+
}, [
|
|
3196
|
+
tab,
|
|
3197
|
+
prompt2,
|
|
3198
|
+
selectedEndpointId,
|
|
3199
|
+
defaultEndpointId,
|
|
3200
|
+
imageService,
|
|
3201
|
+
videoService,
|
|
3202
|
+
pollStatus
|
|
3203
|
+
]);
|
|
3204
|
+
if (!hasAnyService) {
|
|
3205
|
+
return /* @__PURE__ */ jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsx("p", { className: "empty-state-text", children: "Image and video generation require configuration. Add imageGenerationService and videoGenerationService to StudioConfig." }) });
|
|
3206
|
+
}
|
|
3207
|
+
return /* @__PURE__ */ jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxs("div", { className: "panel-section", children: [
|
|
3208
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 mb-2", children: [
|
|
3209
|
+
/* @__PURE__ */ jsx(
|
|
3210
|
+
"button",
|
|
3211
|
+
{
|
|
3212
|
+
type: "button",
|
|
3213
|
+
className: `btn-ghost ${tab === "image" ? "active" : ""}`,
|
|
3214
|
+
onClick: () => setTab("image"),
|
|
3215
|
+
disabled: !imageService,
|
|
3216
|
+
children: "Image"
|
|
3217
|
+
}
|
|
3218
|
+
),
|
|
3219
|
+
/* @__PURE__ */ jsx(
|
|
3220
|
+
"button",
|
|
3221
|
+
{
|
|
3222
|
+
type: "button",
|
|
3223
|
+
className: `btn-ghost ${tab === "video" ? "active" : ""}`,
|
|
3224
|
+
onClick: () => setTab("video"),
|
|
3225
|
+
disabled: !videoService,
|
|
3226
|
+
children: "Video"
|
|
3227
|
+
}
|
|
3228
|
+
)
|
|
3229
|
+
] }),
|
|
3230
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
3231
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm mb-1", children: "Model" }),
|
|
3232
|
+
/* @__PURE__ */ jsx(
|
|
3233
|
+
"select",
|
|
3234
|
+
{
|
|
3235
|
+
className: "w-full p-2 border rounded",
|
|
3236
|
+
value: selectedEndpointId,
|
|
3237
|
+
onChange: (e) => setSelectedEndpointId(e.target.value),
|
|
3238
|
+
disabled: isGenerating,
|
|
3239
|
+
children: endpoints.map((ep) => /* @__PURE__ */ jsx("option", { value: ep.endpointId, children: ep.label }, ep.endpointId))
|
|
3240
|
+
}
|
|
3241
|
+
)
|
|
3242
|
+
] }),
|
|
3243
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
3244
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm mb-1", children: "Prompt" }),
|
|
3245
|
+
/* @__PURE__ */ jsx(
|
|
3246
|
+
"textarea",
|
|
3247
|
+
{
|
|
3248
|
+
className: "w-full p-2 border rounded min-h-[80px]",
|
|
3249
|
+
value: prompt2,
|
|
3250
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
3251
|
+
placeholder: "Describe the image or video you want...",
|
|
3252
|
+
disabled: isGenerating
|
|
3253
|
+
}
|
|
3254
|
+
)
|
|
3255
|
+
] }),
|
|
3256
|
+
error && /* @__PURE__ */ jsx("div", { className: "mb-2 text-red-600 text-sm", children: error }),
|
|
3257
|
+
status && /* @__PURE__ */ jsx("div", { className: "mb-2 text-sm text-gray-600", children: status }),
|
|
3258
|
+
/* @__PURE__ */ jsx(
|
|
3259
|
+
"button",
|
|
3260
|
+
{
|
|
3261
|
+
type: "button",
|
|
3262
|
+
className: "btn-primary w-full",
|
|
3263
|
+
onClick: handleGenerate,
|
|
3264
|
+
disabled: isGenerating || !prompt2.trim(),
|
|
3265
|
+
children: isGenerating ? "Generating..." : `Generate ${tab}`
|
|
3266
|
+
}
|
|
3267
|
+
)
|
|
3268
|
+
] }) });
|
|
3269
|
+
}
|
|
2921
3270
|
const ElementPanelContainer = ({
|
|
2922
3271
|
selectedTool,
|
|
2923
3272
|
videoResolution,
|
|
2924
3273
|
selectedElement,
|
|
2925
3274
|
addElement,
|
|
2926
3275
|
updateElement,
|
|
2927
|
-
uploadConfig
|
|
3276
|
+
uploadConfig,
|
|
3277
|
+
studioConfig
|
|
2928
3278
|
}) => {
|
|
2929
3279
|
const addNewElement = async (element) => {
|
|
2930
3280
|
await addElement(element);
|
|
@@ -2995,6 +3345,17 @@ const ElementPanelContainer = ({
|
|
|
2995
3345
|
);
|
|
2996
3346
|
case "caption":
|
|
2997
3347
|
return /* @__PURE__ */ jsx(CaptionsPanelContainer, {});
|
|
3348
|
+
case "generate-media":
|
|
3349
|
+
return /* @__PURE__ */ jsx(
|
|
3350
|
+
GenerateMediaPanelContainer,
|
|
3351
|
+
{
|
|
3352
|
+
videoResolution,
|
|
3353
|
+
selectedElement,
|
|
3354
|
+
addElement: addNewElement,
|
|
3355
|
+
updateElement,
|
|
3356
|
+
studioConfig
|
|
3357
|
+
}
|
|
3358
|
+
);
|
|
2998
3359
|
default:
|
|
2999
3360
|
return /* @__PURE__ */ jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxs("div", { className: "empty-state-content", children: [
|
|
3000
3361
|
/* @__PURE__ */ jsx(WandSparkles, { className: "empty-state-icon" }),
|
|
@@ -3469,6 +3830,258 @@ function Animation({
|
|
|
3469
3830
|
})() })
|
|
3470
3831
|
] });
|
|
3471
3832
|
}
|
|
3833
|
+
const CAPTION_FONT2 = {
|
|
3834
|
+
size: 40,
|
|
3835
|
+
family: "Bangers"
|
|
3836
|
+
};
|
|
3837
|
+
const CAPTION_COLOR2 = {
|
|
3838
|
+
text: "#ffffff",
|
|
3839
|
+
highlight: "#ff4081",
|
|
3840
|
+
bgColor: "#8C52FF",
|
|
3841
|
+
outlineColor: "#000000"
|
|
3842
|
+
};
|
|
3843
|
+
function CaptionPropPanel({
|
|
3844
|
+
selectedElement,
|
|
3845
|
+
updateElement
|
|
3846
|
+
}) {
|
|
3847
|
+
const { editor, changeLog } = useTimelineContext();
|
|
3848
|
+
const captionRef = useRef(null);
|
|
3849
|
+
const [capStyle, setCapStyle] = useState(
|
|
3850
|
+
CAPTION_STYLE_OPTIONS[CAPTION_STYLE.WORD_BG_HIGHLIGHT]
|
|
3851
|
+
);
|
|
3852
|
+
const [fontSize, setFontSize] = useState(CAPTION_FONT2.size);
|
|
3853
|
+
const [fontFamily, setFontFamily] = useState(CAPTION_FONT2.family);
|
|
3854
|
+
const [colors, setColors] = useState({
|
|
3855
|
+
text: CAPTION_COLOR2.text,
|
|
3856
|
+
highlight: CAPTION_COLOR2.highlight,
|
|
3857
|
+
bgColor: CAPTION_COLOR2.bgColor,
|
|
3858
|
+
outlineColor: CAPTION_COLOR2.outlineColor
|
|
3859
|
+
});
|
|
3860
|
+
const track = selectedElement instanceof CaptionElement ? editor.getTrackById(selectedElement.getTrackId()) : null;
|
|
3861
|
+
const trackProps = (track == null ? void 0 : track.getProps()) ?? {};
|
|
3862
|
+
const applyToAll = (trackProps == null ? void 0 : trackProps.applyToAll) ?? false;
|
|
3863
|
+
const handleUpdateCaption = (updates) => {
|
|
3864
|
+
const captionElement = selectedElement;
|
|
3865
|
+
if (!captionElement) return;
|
|
3866
|
+
if (applyToAll && track) {
|
|
3867
|
+
const nextFont = {
|
|
3868
|
+
size: updates.fontSize ?? fontSize,
|
|
3869
|
+
family: updates.fontFamily ?? fontFamily
|
|
3870
|
+
};
|
|
3871
|
+
const nextColors = updates.colors ?? colors;
|
|
3872
|
+
const nextCapStyle = updates.style ?? (capStyle == null ? void 0 : capStyle.value);
|
|
3873
|
+
track.setProps({
|
|
3874
|
+
...trackProps,
|
|
3875
|
+
capStyle: nextCapStyle,
|
|
3876
|
+
font: { ...(trackProps == null ? void 0 : trackProps.font) ?? {}, ...nextFont },
|
|
3877
|
+
colors: nextColors
|
|
3878
|
+
});
|
|
3879
|
+
editor.refresh();
|
|
3880
|
+
} else {
|
|
3881
|
+
const elementProps = captionElement.getProps() ?? {};
|
|
3882
|
+
captionElement.setProps({
|
|
3883
|
+
...elementProps,
|
|
3884
|
+
capStyle: updates.style ?? (capStyle == null ? void 0 : capStyle.value),
|
|
3885
|
+
font: {
|
|
3886
|
+
size: updates.fontSize ?? fontSize,
|
|
3887
|
+
family: updates.fontFamily ?? fontFamily
|
|
3888
|
+
},
|
|
3889
|
+
colors: updates.colors ?? colors
|
|
3890
|
+
});
|
|
3891
|
+
updateElement == null ? void 0 : updateElement(captionElement);
|
|
3892
|
+
}
|
|
3893
|
+
};
|
|
3894
|
+
useEffect(() => {
|
|
3895
|
+
var _a, _b;
|
|
3896
|
+
const captionElement = selectedElement;
|
|
3897
|
+
if (captionElement) {
|
|
3898
|
+
if (captionRef.current) {
|
|
3899
|
+
captionRef.current.value = captionElement == null ? void 0 : captionElement.getText();
|
|
3900
|
+
}
|
|
3901
|
+
const props = applyToAll ? trackProps : captionElement.getProps() ?? {};
|
|
3902
|
+
const _capStyle = props == null ? void 0 : props.capStyle;
|
|
3903
|
+
if (_capStyle && _capStyle in CAPTION_STYLE_OPTIONS) {
|
|
3904
|
+
setCapStyle(CAPTION_STYLE_OPTIONS[_capStyle]);
|
|
3905
|
+
}
|
|
3906
|
+
setFontSize(((_a = props == null ? void 0 : props.font) == null ? void 0 : _a.size) ?? CAPTION_FONT2.size);
|
|
3907
|
+
setFontFamily(((_b = props == null ? void 0 : props.font) == null ? void 0 : _b.family) ?? CAPTION_FONT2.family);
|
|
3908
|
+
const c = props == null ? void 0 : props.colors;
|
|
3909
|
+
setColors({
|
|
3910
|
+
text: (c == null ? void 0 : c.text) ?? CAPTION_COLOR2.text,
|
|
3911
|
+
highlight: (c == null ? void 0 : c.highlight) ?? CAPTION_COLOR2.highlight,
|
|
3912
|
+
bgColor: (c == null ? void 0 : c.bgColor) ?? CAPTION_COLOR2.bgColor,
|
|
3913
|
+
outlineColor: (c == null ? void 0 : c.outlineColor) ?? CAPTION_COLOR2.outlineColor
|
|
3914
|
+
});
|
|
3915
|
+
}
|
|
3916
|
+
}, [selectedElement, applyToAll, changeLog]);
|
|
3917
|
+
if (!(selectedElement instanceof CaptionElement)) {
|
|
3918
|
+
return null;
|
|
3919
|
+
}
|
|
3920
|
+
return /* @__PURE__ */ jsxs("div", { className: "panel-container", children: [
|
|
3921
|
+
/* @__PURE__ */ jsxs("div", { className: "panel-section", children: [
|
|
3922
|
+
/* @__PURE__ */ jsx("label", { className: "label-dark", children: "Caption Style" }),
|
|
3923
|
+
/* @__PURE__ */ jsx(
|
|
3924
|
+
"select",
|
|
3925
|
+
{
|
|
3926
|
+
value: capStyle.value,
|
|
3927
|
+
onChange: (e) => {
|
|
3928
|
+
const val = e.target.value;
|
|
3929
|
+
if (val in CAPTION_STYLE_OPTIONS) {
|
|
3930
|
+
setCapStyle(CAPTION_STYLE_OPTIONS[val]);
|
|
3931
|
+
}
|
|
3932
|
+
handleUpdateCaption({ style: e.target.value });
|
|
3933
|
+
},
|
|
3934
|
+
className: "select-dark w-full",
|
|
3935
|
+
children: Object.values(CAPTION_STYLE_OPTIONS).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
|
|
3936
|
+
}
|
|
3937
|
+
)
|
|
3938
|
+
] }),
|
|
3939
|
+
/* @__PURE__ */ jsxs("div", { className: "panel-section", children: [
|
|
3940
|
+
/* @__PURE__ */ jsx("label", { className: "label-dark", children: "Font Size" }),
|
|
3941
|
+
/* @__PURE__ */ jsxs("div", { className: "slider-container", children: [
|
|
3942
|
+
/* @__PURE__ */ jsx(
|
|
3943
|
+
"input",
|
|
3944
|
+
{
|
|
3945
|
+
type: "range",
|
|
3946
|
+
min: "8",
|
|
3947
|
+
max: "72",
|
|
3948
|
+
step: "1",
|
|
3949
|
+
value: fontSize,
|
|
3950
|
+
onChange: (e) => {
|
|
3951
|
+
const value = Number(e.target.value);
|
|
3952
|
+
setFontSize(value);
|
|
3953
|
+
handleUpdateCaption({ fontSize: value });
|
|
3954
|
+
},
|
|
3955
|
+
className: "slider-purple"
|
|
3956
|
+
}
|
|
3957
|
+
),
|
|
3958
|
+
/* @__PURE__ */ jsxs("span", { className: "slider-value", children: [
|
|
3959
|
+
fontSize,
|
|
3960
|
+
"px"
|
|
3961
|
+
] })
|
|
3962
|
+
] })
|
|
3963
|
+
] }),
|
|
3964
|
+
/* @__PURE__ */ jsxs("div", { className: "panel-section", children: [
|
|
3965
|
+
/* @__PURE__ */ jsx("label", { className: "label-dark", children: "Font" }),
|
|
3966
|
+
/* @__PURE__ */ jsxs(
|
|
3967
|
+
"select",
|
|
3968
|
+
{
|
|
3969
|
+
value: fontFamily,
|
|
3970
|
+
onChange: (e) => {
|
|
3971
|
+
const value = e.target.value;
|
|
3972
|
+
setFontFamily(value);
|
|
3973
|
+
handleUpdateCaption({ fontFamily: value });
|
|
3974
|
+
},
|
|
3975
|
+
className: "select-dark w-full",
|
|
3976
|
+
children: [
|
|
3977
|
+
/* @__PURE__ */ jsx("option", { value: "Bangers", children: "Bangers" }),
|
|
3978
|
+
/* @__PURE__ */ jsx("option", { value: "Arial", children: "Arial" }),
|
|
3979
|
+
/* @__PURE__ */ jsx("option", { value: "Helvetica", children: "Helvetica" }),
|
|
3980
|
+
/* @__PURE__ */ jsx("option", { value: "Times New Roman", children: "Times New Roman" })
|
|
3981
|
+
]
|
|
3982
|
+
}
|
|
3983
|
+
)
|
|
3984
|
+
] }),
|
|
3985
|
+
/* @__PURE__ */ jsxs("div", { className: "panel-section", children: [
|
|
3986
|
+
/* @__PURE__ */ jsx("label", { className: "label-dark", children: "Colors" }),
|
|
3987
|
+
/* @__PURE__ */ jsxs("div", { className: "color-section", children: [
|
|
3988
|
+
/* @__PURE__ */ jsxs("div", { className: "color-control", children: [
|
|
3989
|
+
/* @__PURE__ */ jsx("label", { className: "label-small", children: "Text Color" }),
|
|
3990
|
+
/* @__PURE__ */ jsxs("div", { className: "color-inputs", children: [
|
|
3991
|
+
/* @__PURE__ */ jsx(
|
|
3992
|
+
"input",
|
|
3993
|
+
{
|
|
3994
|
+
type: "color",
|
|
3995
|
+
value: colors.text,
|
|
3996
|
+
onChange: (e) => {
|
|
3997
|
+
const newColors = { ...colors, text: e.target.value };
|
|
3998
|
+
setColors(newColors);
|
|
3999
|
+
handleUpdateCaption({ colors: newColors });
|
|
4000
|
+
},
|
|
4001
|
+
className: "color-picker"
|
|
4002
|
+
}
|
|
4003
|
+
),
|
|
4004
|
+
/* @__PURE__ */ jsx(
|
|
4005
|
+
"input",
|
|
4006
|
+
{
|
|
4007
|
+
type: "text",
|
|
4008
|
+
value: colors.text,
|
|
4009
|
+
onChange: (e) => {
|
|
4010
|
+
const newColors = { ...colors, text: e.target.value };
|
|
4011
|
+
setColors(newColors);
|
|
4012
|
+
handleUpdateCaption({ colors: newColors });
|
|
4013
|
+
},
|
|
4014
|
+
className: "color-text"
|
|
4015
|
+
}
|
|
4016
|
+
)
|
|
4017
|
+
] })
|
|
4018
|
+
] }),
|
|
4019
|
+
/* @__PURE__ */ jsxs("div", { className: "color-control", children: [
|
|
4020
|
+
/* @__PURE__ */ jsx("label", { className: "label-small", children: "Background Color" }),
|
|
4021
|
+
/* @__PURE__ */ jsxs("div", { className: "color-inputs", children: [
|
|
4022
|
+
/* @__PURE__ */ jsx(
|
|
4023
|
+
"input",
|
|
4024
|
+
{
|
|
4025
|
+
type: "color",
|
|
4026
|
+
value: colors.bgColor,
|
|
4027
|
+
onChange: (e) => {
|
|
4028
|
+
const newColors = { ...colors, bgColor: e.target.value };
|
|
4029
|
+
setColors(newColors);
|
|
4030
|
+
handleUpdateCaption({ colors: newColors });
|
|
4031
|
+
},
|
|
4032
|
+
className: "color-picker"
|
|
4033
|
+
}
|
|
4034
|
+
),
|
|
4035
|
+
/* @__PURE__ */ jsx(
|
|
4036
|
+
"input",
|
|
4037
|
+
{
|
|
4038
|
+
type: "text",
|
|
4039
|
+
value: colors.bgColor,
|
|
4040
|
+
onChange: (e) => {
|
|
4041
|
+
const newColors = { ...colors, bgColor: e.target.value };
|
|
4042
|
+
setColors(newColors);
|
|
4043
|
+
handleUpdateCaption({ colors: newColors });
|
|
4044
|
+
},
|
|
4045
|
+
className: "color-text"
|
|
4046
|
+
}
|
|
4047
|
+
)
|
|
4048
|
+
] })
|
|
4049
|
+
] }),
|
|
4050
|
+
/* @__PURE__ */ jsxs("div", { className: "color-control", children: [
|
|
4051
|
+
/* @__PURE__ */ jsx("label", { className: "label-small", children: "Outline Color" }),
|
|
4052
|
+
/* @__PURE__ */ jsxs("div", { className: "color-inputs", children: [
|
|
4053
|
+
/* @__PURE__ */ jsx(
|
|
4054
|
+
"input",
|
|
4055
|
+
{
|
|
4056
|
+
type: "color",
|
|
4057
|
+
value: colors.outlineColor,
|
|
4058
|
+
onChange: (e) => {
|
|
4059
|
+
const newColors = { ...colors, outlineColor: e.target.value };
|
|
4060
|
+
setColors(newColors);
|
|
4061
|
+
handleUpdateCaption({ colors: newColors });
|
|
4062
|
+
},
|
|
4063
|
+
className: "color-picker"
|
|
4064
|
+
}
|
|
4065
|
+
),
|
|
4066
|
+
/* @__PURE__ */ jsx(
|
|
4067
|
+
"input",
|
|
4068
|
+
{
|
|
4069
|
+
type: "text",
|
|
4070
|
+
value: colors.outlineColor,
|
|
4071
|
+
onChange: (e) => {
|
|
4072
|
+
const newColors = { ...colors, outlineColor: e.target.value };
|
|
4073
|
+
setColors(newColors);
|
|
4074
|
+
handleUpdateCaption({ colors: newColors });
|
|
4075
|
+
},
|
|
4076
|
+
className: "color-text"
|
|
4077
|
+
}
|
|
4078
|
+
)
|
|
4079
|
+
] })
|
|
4080
|
+
] })
|
|
4081
|
+
] })
|
|
4082
|
+
] })
|
|
4083
|
+
] });
|
|
4084
|
+
}
|
|
3472
4085
|
const MIN_DB = -60;
|
|
3473
4086
|
const MAX_DB = 6;
|
|
3474
4087
|
function linearToDb(linear) {
|
|
@@ -3916,6 +4529,7 @@ function TextPropsPanel({
|
|
|
3916
4529
|
)
|
|
3917
4530
|
] });
|
|
3918
4531
|
}
|
|
4532
|
+
const DEFAULT_CANVAS_BACKGROUND = "#000000";
|
|
3919
4533
|
function PropertiesPanelContainer({
|
|
3920
4534
|
selectedElement,
|
|
3921
4535
|
updateElement,
|
|
@@ -3925,26 +4539,66 @@ function PropertiesPanelContainer({
|
|
|
3925
4539
|
pollingIntervalMs,
|
|
3926
4540
|
videoResolution
|
|
3927
4541
|
}) {
|
|
4542
|
+
const { editor, present } = useTimelineContext();
|
|
4543
|
+
const backgroundColor = (present == null ? void 0 : present.backgroundColor) ?? editor.getBackgroundColor() ?? DEFAULT_CANVAS_BACKGROUND;
|
|
4544
|
+
const handleBackgroundColorChange = useCallback(
|
|
4545
|
+
(value) => {
|
|
4546
|
+
editor.setBackgroundColor(value);
|
|
4547
|
+
},
|
|
4548
|
+
[editor]
|
|
4549
|
+
);
|
|
3928
4550
|
const title = selectedElement instanceof TextElement ? selectedElement.getText() : (selectedElement == null ? void 0 : selectedElement.getName()) || (selectedElement == null ? void 0 : selectedElement.getType()) || "Element";
|
|
3929
4551
|
return /* @__PURE__ */ jsxs("aside", { className: "properties-panel", "aria-label": "Element properties inspector", children: [
|
|
3930
4552
|
/* @__PURE__ */ jsxs("div", { className: "properties-header", children: [
|
|
3931
4553
|
!selectedElement && /* @__PURE__ */ jsx("h3", { className: "properties-title", children: "Composition" }),
|
|
3932
|
-
selectedElement && selectedElement.getType() === "caption" && /* @__PURE__ */ jsx("h3", { className: "properties-title", children: "
|
|
4554
|
+
selectedElement && selectedElement.getType() === "caption" && /* @__PURE__ */ jsx("h3", { className: "properties-title", children: "Caption" }),
|
|
3933
4555
|
selectedElement && selectedElement.getType() !== "caption" && /* @__PURE__ */ jsx("h3", { className: "properties-title", children: title })
|
|
3934
4556
|
] }),
|
|
3935
4557
|
/* @__PURE__ */ jsxs("div", { className: "prop-content", children: [
|
|
3936
4558
|
!selectedElement && /* @__PURE__ */ jsxs("div", { className: "panel-container", children: [
|
|
3937
4559
|
/* @__PURE__ */ jsx("div", { className: "panel-title", children: "Canvas & Render" }),
|
|
3938
|
-
/* @__PURE__ */
|
|
3939
|
-
/* @__PURE__ */
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
4560
|
+
/* @__PURE__ */ jsxs("div", { className: "properties-group", children: [
|
|
4561
|
+
/* @__PURE__ */ jsxs("div", { className: "property-section", children: [
|
|
4562
|
+
/* @__PURE__ */ jsx("span", { className: "property-label", children: "Size" }),
|
|
4563
|
+
/* @__PURE__ */ jsxs("span", { className: "properties-size-readonly", children: [
|
|
4564
|
+
videoResolution.width,
|
|
4565
|
+
" × ",
|
|
4566
|
+
videoResolution.height
|
|
4567
|
+
] })
|
|
4568
|
+
] }),
|
|
4569
|
+
/* @__PURE__ */ jsxs("div", { className: "color-control", children: [
|
|
4570
|
+
/* @__PURE__ */ jsx("label", { className: "label-small", children: "Background Color" }),
|
|
4571
|
+
/* @__PURE__ */ jsxs("div", { className: "color-inputs", children: [
|
|
4572
|
+
/* @__PURE__ */ jsx(
|
|
4573
|
+
"input",
|
|
4574
|
+
{
|
|
4575
|
+
type: "color",
|
|
4576
|
+
value: backgroundColor,
|
|
4577
|
+
onChange: (e) => handleBackgroundColorChange(e.target.value),
|
|
4578
|
+
className: "color-picker"
|
|
4579
|
+
}
|
|
4580
|
+
),
|
|
4581
|
+
/* @__PURE__ */ jsx(
|
|
4582
|
+
"input",
|
|
4583
|
+
{
|
|
4584
|
+
type: "text",
|
|
4585
|
+
value: backgroundColor,
|
|
4586
|
+
onChange: (e) => handleBackgroundColorChange(e.target.value),
|
|
4587
|
+
className: "color-text"
|
|
4588
|
+
}
|
|
4589
|
+
)
|
|
4590
|
+
] })
|
|
3944
4591
|
] })
|
|
3945
|
-
] })
|
|
4592
|
+
] })
|
|
3946
4593
|
] }),
|
|
3947
|
-
selectedElement
|
|
4594
|
+
selectedElement instanceof CaptionElement && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
4595
|
+
CaptionPropPanel,
|
|
4596
|
+
{
|
|
4597
|
+
selectedElement,
|
|
4598
|
+
updateElement
|
|
4599
|
+
}
|
|
4600
|
+
) }),
|
|
4601
|
+
selectedElement && !(selectedElement instanceof CaptionElement) && /* @__PURE__ */ jsx(Fragment, { children: (() => {
|
|
3948
4602
|
const isText = selectedElement instanceof TextElement;
|
|
3949
4603
|
const isVideo = selectedElement instanceof VideoElement;
|
|
3950
4604
|
const isAudio = selectedElement instanceof AudioElement;
|
|
@@ -4106,7 +4760,7 @@ function TwickStudio({ studioConfig }) {
|
|
|
4106
4760
|
addElement,
|
|
4107
4761
|
updateElement
|
|
4108
4762
|
} = useStudioManager();
|
|
4109
|
-
const { videoResolution, setVideoResolution } = useTimelineContext();
|
|
4763
|
+
const { editor, present, videoResolution, setVideoResolution } = useTimelineContext();
|
|
4110
4764
|
const {
|
|
4111
4765
|
onNewProject,
|
|
4112
4766
|
onLoadProject,
|
|
@@ -4120,16 +4774,20 @@ function TwickStudio({ studioConfig }) {
|
|
|
4120
4774
|
pollingIntervalMs
|
|
4121
4775
|
} = useGenerateCaptions(studioConfig);
|
|
4122
4776
|
const twickStudiConfig = useMemo(
|
|
4123
|
-
() =>
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
...
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4777
|
+
() => {
|
|
4778
|
+
var _a2;
|
|
4779
|
+
return {
|
|
4780
|
+
canvasMode: true,
|
|
4781
|
+
...studioConfig || {},
|
|
4782
|
+
videoProps: {
|
|
4783
|
+
...(studioConfig == null ? void 0 : studioConfig.videoProps) || {},
|
|
4784
|
+
width: videoResolution.width,
|
|
4785
|
+
height: videoResolution.height,
|
|
4786
|
+
backgroundColor: (present == null ? void 0 : present.backgroundColor) ?? editor.getBackgroundColor() ?? ((_a2 = studioConfig == null ? void 0 : studioConfig.videoProps) == null ? void 0 : _a2.backgroundColor)
|
|
4787
|
+
}
|
|
4788
|
+
};
|
|
4789
|
+
},
|
|
4790
|
+
[videoResolution, studioConfig, present == null ? void 0 : present.backgroundColor, editor]
|
|
4133
4791
|
);
|
|
4134
4792
|
return /* @__PURE__ */ jsx(MediaProvider, { children: /* @__PURE__ */ jsxs("div", { className: "studio-container", children: [
|
|
4135
4793
|
/* @__PURE__ */ jsx(
|
|
@@ -4159,7 +4817,8 @@ function TwickStudio({ studioConfig }) {
|
|
|
4159
4817
|
selectedElement,
|
|
4160
4818
|
addElement,
|
|
4161
4819
|
updateElement,
|
|
4162
|
-
uploadConfig: twickStudiConfig.uploadConfig
|
|
4820
|
+
uploadConfig: twickStudiConfig.uploadConfig,
|
|
4821
|
+
studioConfig: twickStudiConfig
|
|
4163
4822
|
}
|
|
4164
4823
|
) }),
|
|
4165
4824
|
/* @__PURE__ */ jsx("main", { className: "main-container", children: /* @__PURE__ */ jsx("div", { className: "canvas-wrapper", children: /* @__PURE__ */ jsx(
|
|
@@ -4239,7 +4898,7 @@ export {
|
|
|
4239
4898
|
CAPTION_FONT,
|
|
4240
4899
|
CAPTION_PROPS,
|
|
4241
4900
|
CAPTION_STYLE2 as CAPTION_STYLE,
|
|
4242
|
-
CAPTION_STYLE_OPTIONS,
|
|
4901
|
+
CAPTION_STYLE_OPTIONS2 as CAPTION_STYLE_OPTIONS,
|
|
4243
4902
|
CaptionElement2 as CaptionElement,
|
|
4244
4903
|
CaptionsPanel,
|
|
4245
4904
|
CircleElement2 as CircleElement,
|