@twick/studio 0.14.7 → 0.14.9
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/components/container/element-panel-container.d.ts +26 -1
- package/dist/components/container/subtitles-panel-container.d.ts +1 -0
- package/dist/components/panel/subtitles-panel.d.ts +37 -18
- package/dist/helpers/constant.d.ts +52 -0
- package/dist/hooks/use-studio-manager.d.ts +1 -1
- package/dist/hooks/use-subtitles-panel.d.ts +13 -0
- package/dist/index.js +240 -186
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +242 -188
- package/dist/index.mjs.map +1 -1
- package/dist/studio.css +1 -3
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -110,23 +110,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
110
110
|
* This source code is licensed under the ISC license.
|
|
111
111
|
* See the LICENSE file in the root directory of this source tree.
|
|
112
112
|
*/
|
|
113
|
-
const __iconNode$o = [["
|
|
114
|
-
const
|
|
113
|
+
const __iconNode$o = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
|
|
114
|
+
const Circle = createLucideIcon("circle", __iconNode$o);
|
|
115
115
|
/**
|
|
116
116
|
* @license lucide-react v0.511.0 - ISC
|
|
117
117
|
*
|
|
118
118
|
* This source code is licensed under the ISC license.
|
|
119
119
|
* See the LICENSE file in the root directory of this source tree.
|
|
120
120
|
*/
|
|
121
|
-
const __iconNode$n = [
|
|
122
|
-
const Circle = createLucideIcon("circle", __iconNode$n);
|
|
123
|
-
/**
|
|
124
|
-
* @license lucide-react v0.511.0 - ISC
|
|
125
|
-
*
|
|
126
|
-
* This source code is licensed under the ISC license.
|
|
127
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
128
|
-
*/
|
|
129
|
-
const __iconNode$m = [
|
|
121
|
+
const __iconNode$n = [
|
|
130
122
|
[
|
|
131
123
|
"path",
|
|
132
124
|
{ d: "M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3Z", key: "1tn4o7" }
|
|
@@ -135,119 +127,119 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
135
127
|
["path", { d: "m12.4 3.4 3.1 4", key: "6hsd6n" }],
|
|
136
128
|
["path", { d: "M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z", key: "ltgou9" }]
|
|
137
129
|
];
|
|
138
|
-
const Clapperboard = createLucideIcon("clapperboard", __iconNode$
|
|
130
|
+
const Clapperboard = createLucideIcon("clapperboard", __iconNode$n);
|
|
139
131
|
/**
|
|
140
132
|
* @license lucide-react v0.511.0 - ISC
|
|
141
133
|
*
|
|
142
134
|
* This source code is licensed under the ISC license.
|
|
143
135
|
* See the LICENSE file in the root directory of this source tree.
|
|
144
136
|
*/
|
|
145
|
-
const __iconNode$
|
|
137
|
+
const __iconNode$m = [
|
|
146
138
|
["path", { d: "M12 15V3", key: "m9g1x1" }],
|
|
147
139
|
["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
|
|
148
140
|
["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
|
|
149
141
|
];
|
|
150
|
-
const Download = createLucideIcon("download", __iconNode$
|
|
142
|
+
const Download = createLucideIcon("download", __iconNode$m);
|
|
151
143
|
/**
|
|
152
144
|
* @license lucide-react v0.511.0 - ISC
|
|
153
145
|
*
|
|
154
146
|
* This source code is licensed under the ISC license.
|
|
155
147
|
* See the LICENSE file in the root directory of this source tree.
|
|
156
148
|
*/
|
|
157
|
-
const __iconNode$
|
|
149
|
+
const __iconNode$l = [
|
|
158
150
|
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
159
151
|
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }]
|
|
160
152
|
];
|
|
161
|
-
const File = createLucideIcon("file", __iconNode$
|
|
153
|
+
const File = createLucideIcon("file", __iconNode$l);
|
|
162
154
|
/**
|
|
163
155
|
* @license lucide-react v0.511.0 - ISC
|
|
164
156
|
*
|
|
165
157
|
* This source code is licensed under the ISC license.
|
|
166
158
|
* See the LICENSE file in the root directory of this source tree.
|
|
167
159
|
*/
|
|
168
|
-
const __iconNode$
|
|
160
|
+
const __iconNode$k = [
|
|
169
161
|
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
|
|
170
162
|
["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
|
|
171
163
|
["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
|
|
172
164
|
];
|
|
173
|
-
const Image = createLucideIcon("image", __iconNode$
|
|
165
|
+
const Image = createLucideIcon("image", __iconNode$k);
|
|
174
166
|
/**
|
|
175
167
|
* @license lucide-react v0.511.0 - ISC
|
|
176
168
|
*
|
|
177
169
|
* This source code is licensed under the ISC license.
|
|
178
170
|
* See the LICENSE file in the root directory of this source tree.
|
|
179
171
|
*/
|
|
180
|
-
const __iconNode$
|
|
172
|
+
const __iconNode$j = [
|
|
181
173
|
["path", { d: "M6 16c5 0 7-8 12-8a4 4 0 0 1 0 8c-5 0-7-8-12-8a4 4 0 1 0 0 8", key: "18ogeb" }]
|
|
182
174
|
];
|
|
183
|
-
const Infinity = createLucideIcon("infinity", __iconNode$
|
|
175
|
+
const Infinity = createLucideIcon("infinity", __iconNode$j);
|
|
184
176
|
/**
|
|
185
177
|
* @license lucide-react v0.511.0 - ISC
|
|
186
178
|
*
|
|
187
179
|
* This source code is licensed under the ISC license.
|
|
188
180
|
* See the LICENSE file in the root directory of this source tree.
|
|
189
181
|
*/
|
|
190
|
-
const __iconNode$
|
|
191
|
-
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$
|
|
182
|
+
const __iconNode$i = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
183
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$i);
|
|
192
184
|
/**
|
|
193
185
|
* @license lucide-react v0.511.0 - ISC
|
|
194
186
|
*
|
|
195
187
|
* This source code is licensed under the ISC license.
|
|
196
188
|
* See the LICENSE file in the root directory of this source tree.
|
|
197
189
|
*/
|
|
198
|
-
const __iconNode$
|
|
190
|
+
const __iconNode$h = [
|
|
199
191
|
["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }]
|
|
200
192
|
];
|
|
201
|
-
const MessageSquare = createLucideIcon("message-square", __iconNode$
|
|
193
|
+
const MessageSquare = createLucideIcon("message-square", __iconNode$h);
|
|
202
194
|
/**
|
|
203
195
|
* @license lucide-react v0.511.0 - ISC
|
|
204
196
|
*
|
|
205
197
|
* This source code is licensed under the ISC license.
|
|
206
198
|
* See the LICENSE file in the root directory of this source tree.
|
|
207
199
|
*/
|
|
208
|
-
const __iconNode$
|
|
200
|
+
const __iconNode$g = [
|
|
209
201
|
["path", { d: "M9 18V5l12-2v13", key: "1jmyc2" }],
|
|
210
202
|
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
211
203
|
["circle", { cx: "18", cy: "16", r: "3", key: "1hluhg" }]
|
|
212
204
|
];
|
|
213
|
-
const Music = createLucideIcon("music", __iconNode$
|
|
205
|
+
const Music = createLucideIcon("music", __iconNode$g);
|
|
214
206
|
/**
|
|
215
207
|
* @license lucide-react v0.511.0 - ISC
|
|
216
208
|
*
|
|
217
209
|
* This source code is licensed under the ISC license.
|
|
218
210
|
* See the LICENSE file in the root directory of this source tree.
|
|
219
211
|
*/
|
|
220
|
-
const __iconNode$
|
|
212
|
+
const __iconNode$f = [
|
|
221
213
|
["rect", { x: "14", y: "4", width: "4", height: "16", rx: "1", key: "zuxfzm" }],
|
|
222
214
|
["rect", { x: "6", y: "4", width: "4", height: "16", rx: "1", key: "1okwgv" }]
|
|
223
215
|
];
|
|
224
|
-
const Pause = createLucideIcon("pause", __iconNode$
|
|
216
|
+
const Pause = createLucideIcon("pause", __iconNode$f);
|
|
225
217
|
/**
|
|
226
218
|
* @license lucide-react v0.511.0 - ISC
|
|
227
219
|
*
|
|
228
220
|
* This source code is licensed under the ISC license.
|
|
229
221
|
* See the LICENSE file in the root directory of this source tree.
|
|
230
222
|
*/
|
|
231
|
-
const __iconNode$
|
|
232
|
-
const Play = createLucideIcon("play", __iconNode$
|
|
223
|
+
const __iconNode$e = [["polygon", { points: "6 3 20 12 6 21 6 3", key: "1oa8hb" }]];
|
|
224
|
+
const Play = createLucideIcon("play", __iconNode$e);
|
|
233
225
|
/**
|
|
234
226
|
* @license lucide-react v0.511.0 - ISC
|
|
235
227
|
*
|
|
236
228
|
* This source code is licensed under the ISC license.
|
|
237
229
|
* See the LICENSE file in the root directory of this source tree.
|
|
238
230
|
*/
|
|
239
|
-
const __iconNode$
|
|
231
|
+
const __iconNode$d = [
|
|
240
232
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
241
233
|
["path", { d: "M12 5v14", key: "s699le" }]
|
|
242
234
|
];
|
|
243
|
-
const Plus = createLucideIcon("plus", __iconNode$
|
|
235
|
+
const Plus = createLucideIcon("plus", __iconNode$d);
|
|
244
236
|
/**
|
|
245
237
|
* @license lucide-react v0.511.0 - ISC
|
|
246
238
|
*
|
|
247
239
|
* This source code is licensed under the ISC license.
|
|
248
240
|
* See the LICENSE file in the root directory of this source tree.
|
|
249
241
|
*/
|
|
250
|
-
const __iconNode$
|
|
242
|
+
const __iconNode$c = [
|
|
251
243
|
[
|
|
252
244
|
"path",
|
|
253
245
|
{
|
|
@@ -258,7 +250,21 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
258
250
|
["path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7", key: "1ydtos" }],
|
|
259
251
|
["path", { d: "M7 3v4a1 1 0 0 0 1 1h7", key: "t51u73" }]
|
|
260
252
|
];
|
|
261
|
-
const Save = createLucideIcon("save", __iconNode$
|
|
253
|
+
const Save = createLucideIcon("save", __iconNode$c);
|
|
254
|
+
/**
|
|
255
|
+
* @license lucide-react v0.511.0 - ISC
|
|
256
|
+
*
|
|
257
|
+
* This source code is licensed under the ISC license.
|
|
258
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
259
|
+
*/
|
|
260
|
+
const __iconNode$b = [
|
|
261
|
+
["circle", { cx: "6", cy: "6", r: "3", key: "1lh9wr" }],
|
|
262
|
+
["path", { d: "M8.12 8.12 12 12", key: "1alkpv" }],
|
|
263
|
+
["path", { d: "M20 4 8.12 15.88", key: "xgtan2" }],
|
|
264
|
+
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
265
|
+
["path", { d: "M14.8 14.8 20 20", key: "ptml3r" }]
|
|
266
|
+
];
|
|
267
|
+
const Scissors = createLucideIcon("scissors", __iconNode$b);
|
|
262
268
|
/**
|
|
263
269
|
* @license lucide-react v0.511.0 - ISC
|
|
264
270
|
*
|
|
@@ -436,8 +442,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
436
442
|
{ id: "text", name: "Text", icon: "Type", description: "Add text elements", shortcut: "T" },
|
|
437
443
|
{ id: "icon", name: "Icons", icon: "Icon", description: "Icon Element", shortcut: "I" },
|
|
438
444
|
{ id: "circle", name: "Circle", icon: "Circle", description: "Circle Element", shortcut: "C" },
|
|
439
|
-
{ id: "rect", name: "Rect", icon: "Rect", description: "Rect Element" }
|
|
440
|
-
|
|
445
|
+
{ id: "rect", name: "Rect", icon: "Rect", description: "Rect Element" },
|
|
446
|
+
{ id: "subtitle", name: "Subtitles", icon: "MessageSquare", description: "Manage subtitles", shortcut: "S" }
|
|
441
447
|
];
|
|
442
448
|
const getIcon$1 = (iconName) => {
|
|
443
449
|
switch (iconName) {
|
|
@@ -560,34 +566,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
560
566
|
};
|
|
561
567
|
const useStudioManager = () => {
|
|
562
568
|
const [selectedProp, setSelectedProp] = react.useState("element-props");
|
|
563
|
-
const {
|
|
569
|
+
const { selectedItem } = timeline.useTimelineContext();
|
|
570
|
+
const { addElement, updateElement } = VideoEditor.useEditorManager();
|
|
564
571
|
const selectedElement = selectedItem instanceof timeline.TrackElement ? selectedItem : null;
|
|
565
572
|
const [selectedTool, setSelectedTool] = react.useState("none");
|
|
566
573
|
const isToolChanged = react.useRef(false);
|
|
567
|
-
const addElement = (element) => {
|
|
568
|
-
if (selectedItem instanceof timeline.Track) {
|
|
569
|
-
editor.addElementToTrack(selectedItem, element);
|
|
570
|
-
} else {
|
|
571
|
-
const newTrack = editor.addTrack("Track");
|
|
572
|
-
editor.addElementToTrack(newTrack, element);
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
const updateElement = (element) => {
|
|
576
|
-
const updatedElement = editor.updateElement(element);
|
|
577
|
-
editor.refresh();
|
|
578
|
-
setSelectedItem(updatedElement);
|
|
579
|
-
};
|
|
580
574
|
react.useEffect(() => {
|
|
581
575
|
if (selectedItem instanceof timeline.TrackElement) {
|
|
582
576
|
setSelectedTool(selectedItem.getType());
|
|
583
577
|
isToolChanged.current = true;
|
|
584
578
|
} else if (selectedItem instanceof timeline.Track) ;
|
|
585
579
|
else {
|
|
586
|
-
|
|
587
|
-
setSelectedTool("none");
|
|
588
|
-
} else {
|
|
589
|
-
setSelectedTool("video");
|
|
590
|
-
}
|
|
580
|
+
setSelectedTool("video");
|
|
591
581
|
}
|
|
592
582
|
}, [selectedItem]);
|
|
593
583
|
return {
|
|
@@ -600,131 +590,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
600
590
|
updateElement
|
|
601
591
|
};
|
|
602
592
|
};
|
|
603
|
-
function SubtitlesPanel() {
|
|
604
|
-
const [subtitles, setSubtitles] = react.useState([]);
|
|
605
|
-
const handleGenerate = () => {
|
|
606
|
-
console.log("Generating subtitles...");
|
|
607
|
-
};
|
|
608
|
-
const handleAdd = () => {
|
|
609
|
-
const newId = (subtitles.length + 1).toString();
|
|
610
|
-
const lastEnd = subtitles.length > 0 ? subtitles[subtitles.length - 1].end : 0;
|
|
611
|
-
const newSubtitle = {
|
|
612
|
-
id: newId,
|
|
613
|
-
start: lastEnd,
|
|
614
|
-
end: lastEnd + 1,
|
|
615
|
-
text: ""
|
|
616
|
-
};
|
|
617
|
-
setSubtitles([...subtitles, newSubtitle]);
|
|
618
|
-
};
|
|
619
|
-
const handleDelete = (id) => {
|
|
620
|
-
setSubtitles(subtitles.filter((sub) => sub.id !== id));
|
|
621
|
-
};
|
|
622
|
-
const handleSave = (id) => {
|
|
623
|
-
console.log("Saving subtitle:", id);
|
|
624
|
-
};
|
|
625
|
-
const handleUpdateSubtitle = (id, field, value) => {
|
|
626
|
-
setSubtitles(subtitles.map(
|
|
627
|
-
(sub) => sub.id === id ? { ...sub, [field]: value } : sub
|
|
628
|
-
));
|
|
629
|
-
};
|
|
630
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-container", children: [
|
|
631
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: "Subtitles" }),
|
|
632
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-section", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-container", children: [
|
|
633
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
634
|
-
"button",
|
|
635
|
-
{
|
|
636
|
-
onClick: handleGenerate,
|
|
637
|
-
className: "btn-primary",
|
|
638
|
-
children: "Generate"
|
|
639
|
-
}
|
|
640
|
-
),
|
|
641
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
642
|
-
"button",
|
|
643
|
-
{
|
|
644
|
-
onClick: handleAdd,
|
|
645
|
-
className: "btn-primary",
|
|
646
|
-
children: "Add"
|
|
647
|
-
}
|
|
648
|
-
)
|
|
649
|
-
] }) }),
|
|
650
|
-
subtitles.map((subtitle) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
651
|
-
"div",
|
|
652
|
-
{
|
|
653
|
-
className: "panel-section",
|
|
654
|
-
children: [
|
|
655
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-container", children: [
|
|
656
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
657
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "Start" }),
|
|
658
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
659
|
-
"input",
|
|
660
|
-
{
|
|
661
|
-
type: "number",
|
|
662
|
-
min: "0",
|
|
663
|
-
step: "0.1",
|
|
664
|
-
value: subtitle.start,
|
|
665
|
-
onChange: (e) => handleUpdateSubtitle(subtitle.id, "start", Number(e.target.value)),
|
|
666
|
-
className: "input-dark"
|
|
667
|
-
}
|
|
668
|
-
)
|
|
669
|
-
] }),
|
|
670
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
671
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-small", children: "End" }),
|
|
672
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
673
|
-
"input",
|
|
674
|
-
{
|
|
675
|
-
type: "number",
|
|
676
|
-
min: "0",
|
|
677
|
-
step: "0.1",
|
|
678
|
-
value: subtitle.end,
|
|
679
|
-
onChange: (e) => handleUpdateSubtitle(subtitle.id, "end", Number(e.target.value)),
|
|
680
|
-
className: "input-dark"
|
|
681
|
-
}
|
|
682
|
-
)
|
|
683
|
-
] })
|
|
684
|
-
] }),
|
|
685
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
686
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "label-dark", children: "Subtitle Text" }),
|
|
687
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
688
|
-
"input",
|
|
689
|
-
{
|
|
690
|
-
type: "text",
|
|
691
|
-
placeholder: "Enter subtitle text",
|
|
692
|
-
value: subtitle.text,
|
|
693
|
-
onChange: (e) => handleUpdateSubtitle(subtitle.id, "text", e.target.value),
|
|
694
|
-
className: "input-dark"
|
|
695
|
-
}
|
|
696
|
-
)
|
|
697
|
-
] }),
|
|
698
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-container justify-between", children: [
|
|
699
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
700
|
-
"button",
|
|
701
|
-
{
|
|
702
|
-
onClick: () => handleDelete(subtitle.id),
|
|
703
|
-
className: "btn-danger",
|
|
704
|
-
title: "Delete subtitle",
|
|
705
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { className: "icon-sm" })
|
|
706
|
-
}
|
|
707
|
-
),
|
|
708
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
709
|
-
"button",
|
|
710
|
-
{
|
|
711
|
-
onClick: () => handleSave(subtitle.id),
|
|
712
|
-
className: "btn-primary",
|
|
713
|
-
title: "Save subtitle",
|
|
714
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Check, { className: "icon-sm" })
|
|
715
|
-
}
|
|
716
|
-
)
|
|
717
|
-
] })
|
|
718
|
-
]
|
|
719
|
-
},
|
|
720
|
-
subtitle.id
|
|
721
|
-
)),
|
|
722
|
-
subtitles.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-section", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state-content", children: [
|
|
723
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "No subtitles yet" }),
|
|
724
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-subtext", children: 'Click "Add" to create your first subtitle' })
|
|
725
|
-
] }) }) })
|
|
726
|
-
] });
|
|
727
|
-
}
|
|
728
593
|
const FileInput = ({
|
|
729
594
|
acceptFileTypes,
|
|
730
595
|
onFileLoad,
|
|
@@ -2394,9 +2259,198 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2394
2259
|
});
|
|
2395
2260
|
return /* @__PURE__ */ jsxRuntime.jsx(CirclePanel, { ...circlePanelProps });
|
|
2396
2261
|
}
|
|
2262
|
+
function SubtitlesPanel({
|
|
2263
|
+
subtitles,
|
|
2264
|
+
addSubtitle,
|
|
2265
|
+
splitSubtitle,
|
|
2266
|
+
deleteSubtitle,
|
|
2267
|
+
updateSubtitle
|
|
2268
|
+
}) {
|
|
2269
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "panel-container", children: [
|
|
2270
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: "Subtitles" }),
|
|
2271
|
+
subtitles.map((subtitle, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2272
|
+
"div",
|
|
2273
|
+
{
|
|
2274
|
+
className: "panel-section gap-2",
|
|
2275
|
+
children: [
|
|
2276
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2277
|
+
"input",
|
|
2278
|
+
{
|
|
2279
|
+
type: "text",
|
|
2280
|
+
placeholder: "Enter subtitle text",
|
|
2281
|
+
value: subtitle.t,
|
|
2282
|
+
onChange: (e) => updateSubtitle(i, { ...subtitle, t: e.target.value }),
|
|
2283
|
+
className: "input-dark"
|
|
2284
|
+
}
|
|
2285
|
+
) }),
|
|
2286
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-container justify-between", children: [
|
|
2287
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2288
|
+
"button",
|
|
2289
|
+
{
|
|
2290
|
+
onClick: () => splitSubtitle(i),
|
|
2291
|
+
className: "btn-ghost",
|
|
2292
|
+
title: "Split subtitle",
|
|
2293
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Scissors, { className: "icon-sm" })
|
|
2294
|
+
}
|
|
2295
|
+
),
|
|
2296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2297
|
+
"button",
|
|
2298
|
+
{
|
|
2299
|
+
onClick: () => deleteSubtitle(i),
|
|
2300
|
+
className: "btn-ghost",
|
|
2301
|
+
title: "Delete subtitle",
|
|
2302
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { className: "icon-sm", color: "var(--color-red-500)" })
|
|
2303
|
+
}
|
|
2304
|
+
)
|
|
2305
|
+
] })
|
|
2306
|
+
]
|
|
2307
|
+
},
|
|
2308
|
+
i
|
|
2309
|
+
)),
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-section", children: /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: addSubtitle, className: "btn-primary w-full", title: "Add subtitle", children: "Add" }) })
|
|
2311
|
+
] });
|
|
2312
|
+
}
|
|
2313
|
+
const CAPTION_PROPS = {
|
|
2314
|
+
[timeline.CAPTION_STYLE.WORD_BG_HIGHLIGHT]: {
|
|
2315
|
+
font: {
|
|
2316
|
+
size: 50,
|
|
2317
|
+
weight: 700,
|
|
2318
|
+
family: "Bangers"
|
|
2319
|
+
},
|
|
2320
|
+
colors: {
|
|
2321
|
+
text: "#ffffff",
|
|
2322
|
+
highlight: "#ff4081",
|
|
2323
|
+
bgColor: "#444444"
|
|
2324
|
+
},
|
|
2325
|
+
lineWidth: 0.35,
|
|
2326
|
+
stroke: "#000000",
|
|
2327
|
+
fontWeight: 700,
|
|
2328
|
+
shadowOffset: [-3, 3],
|
|
2329
|
+
shadowColor: "#000000"
|
|
2330
|
+
},
|
|
2331
|
+
[timeline.CAPTION_STYLE.WORD_BY_WORD]: {
|
|
2332
|
+
font: {
|
|
2333
|
+
size: 50,
|
|
2334
|
+
weight: 700,
|
|
2335
|
+
family: "Bangers"
|
|
2336
|
+
},
|
|
2337
|
+
colors: {
|
|
2338
|
+
text: "#ffffff",
|
|
2339
|
+
highlight: "#ff4081",
|
|
2340
|
+
bgColor: "#444444"
|
|
2341
|
+
},
|
|
2342
|
+
lineWidth: 0.35,
|
|
2343
|
+
stroke: "#000000",
|
|
2344
|
+
shadowOffset: [-2, 2],
|
|
2345
|
+
shadowColor: "#000000",
|
|
2346
|
+
shadowBlur: 5
|
|
2347
|
+
},
|
|
2348
|
+
[timeline.CAPTION_STYLE.WORD_BY_WORD_WITH_BG]: {
|
|
2349
|
+
font: {
|
|
2350
|
+
size: 50,
|
|
2351
|
+
weight: 700,
|
|
2352
|
+
family: "Bangers"
|
|
2353
|
+
},
|
|
2354
|
+
colors: {
|
|
2355
|
+
text: "#ffffff",
|
|
2356
|
+
highlight: "#ff4081",
|
|
2357
|
+
bgColor: "#444444"
|
|
2358
|
+
},
|
|
2359
|
+
lineWidth: 0.35,
|
|
2360
|
+
shadowOffset: [-2, 2],
|
|
2361
|
+
shadowColor: "#000000",
|
|
2362
|
+
shadowBlur: 5
|
|
2363
|
+
}
|
|
2364
|
+
};
|
|
2365
|
+
const useSubtitlesPanel = () => {
|
|
2366
|
+
const [subtitles, setSubtitles] = react.useState([]);
|
|
2367
|
+
const subtitlesTrack = react.useRef(null);
|
|
2368
|
+
const { editor } = timeline.useTimelineContext();
|
|
2369
|
+
const fetchSubtitles = async () => {
|
|
2370
|
+
const editorSubtitlesTrack = editor.getSubtiltesTrack();
|
|
2371
|
+
if (editorSubtitlesTrack) {
|
|
2372
|
+
subtitlesTrack.current = editorSubtitlesTrack;
|
|
2373
|
+
setSubtitles(
|
|
2374
|
+
editorSubtitlesTrack.getElements().map((element) => ({
|
|
2375
|
+
s: element.getStart(),
|
|
2376
|
+
e: element.getEnd(),
|
|
2377
|
+
t: element.getText()
|
|
2378
|
+
}))
|
|
2379
|
+
);
|
|
2380
|
+
}
|
|
2381
|
+
};
|
|
2382
|
+
react.useEffect(() => {
|
|
2383
|
+
fetchSubtitles();
|
|
2384
|
+
}, []);
|
|
2385
|
+
const checkSubtitlesTrack = () => {
|
|
2386
|
+
var _a;
|
|
2387
|
+
if (!subtitlesTrack.current) {
|
|
2388
|
+
subtitlesTrack.current = editor.addTrack("Subtitles", "caption");
|
|
2389
|
+
const props = {
|
|
2390
|
+
capStyle: timeline.CAPTION_STYLE.WORD_BG_HIGHLIGHT,
|
|
2391
|
+
...CAPTION_PROPS[timeline.CAPTION_STYLE.WORD_BG_HIGHLIGHT],
|
|
2392
|
+
x: 0,
|
|
2393
|
+
y: 200,
|
|
2394
|
+
applyToAll: true
|
|
2395
|
+
};
|
|
2396
|
+
(_a = subtitlesTrack.current) == null ? void 0 : _a.setProps(props);
|
|
2397
|
+
}
|
|
2398
|
+
};
|
|
2399
|
+
const addSubtitle = () => {
|
|
2400
|
+
const newSubtitle = { s: 0, e: 0, t: "New Subtitle" };
|
|
2401
|
+
if (subtitles.length > 0) {
|
|
2402
|
+
newSubtitle.s = subtitles[subtitles.length - 1].e;
|
|
2403
|
+
}
|
|
2404
|
+
newSubtitle.e = newSubtitle.s + 1;
|
|
2405
|
+
setSubtitles([...subtitles, newSubtitle]);
|
|
2406
|
+
checkSubtitlesTrack();
|
|
2407
|
+
const captionElement = new timeline.CaptionElement(
|
|
2408
|
+
newSubtitle.t,
|
|
2409
|
+
newSubtitle.s,
|
|
2410
|
+
newSubtitle.e
|
|
2411
|
+
);
|
|
2412
|
+
editor.addElementToTrack(subtitlesTrack.current, captionElement);
|
|
2413
|
+
};
|
|
2414
|
+
const splitSubtitle = async (index) => {
|
|
2415
|
+
if (subtitlesTrack.current) {
|
|
2416
|
+
const element = subtitlesTrack.current.getElements()[index];
|
|
2417
|
+
const splitResult = await editor.splitElement(
|
|
2418
|
+
element,
|
|
2419
|
+
element.getStart() + element.getDuration() / 2
|
|
2420
|
+
);
|
|
2421
|
+
if (splitResult.success) {
|
|
2422
|
+
fetchSubtitles();
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
};
|
|
2426
|
+
const deleteSubtitle = (index) => {
|
|
2427
|
+
setSubtitles(subtitles.filter((_, i) => i !== index));
|
|
2428
|
+
if (subtitlesTrack.current) {
|
|
2429
|
+
editor.removeElement(subtitlesTrack.current.getElements()[index]);
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
const updateSubtitle = (index, subtitle) => {
|
|
2433
|
+
setSubtitles(subtitles.map((sub, i) => i === index ? subtitle : sub));
|
|
2434
|
+
if (subtitlesTrack.current) {
|
|
2435
|
+
const element = subtitlesTrack.current.getElements()[index];
|
|
2436
|
+
element.setText(subtitle.t);
|
|
2437
|
+
editor.updateElement(element);
|
|
2438
|
+
}
|
|
2439
|
+
};
|
|
2440
|
+
return {
|
|
2441
|
+
subtitles,
|
|
2442
|
+
addSubtitle,
|
|
2443
|
+
splitSubtitle,
|
|
2444
|
+
deleteSubtitle,
|
|
2445
|
+
updateSubtitle
|
|
2446
|
+
};
|
|
2447
|
+
};
|
|
2448
|
+
function SubtitlesPanelContainer() {
|
|
2449
|
+
const subtitlesPanelProps = useSubtitlesPanel();
|
|
2450
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SubtitlesPanel, { ...subtitlesPanelProps });
|
|
2451
|
+
}
|
|
2397
2452
|
const ElementPanelContainer = ({
|
|
2398
2453
|
selectedTool,
|
|
2399
|
-
setSelectedTool,
|
|
2400
2454
|
videoResolution,
|
|
2401
2455
|
selectedElement,
|
|
2402
2456
|
addElement,
|
|
@@ -2404,9 +2458,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2404
2458
|
}) => {
|
|
2405
2459
|
const addNewElement = async (element) => {
|
|
2406
2460
|
await addElement(element);
|
|
2407
|
-
if (!["image", "video", "audio"].includes(selectedTool)) {
|
|
2408
|
-
setSelectedTool("none");
|
|
2409
|
-
}
|
|
2410
2461
|
};
|
|
2411
2462
|
const renderLibrary = () => {
|
|
2412
2463
|
switch (selectedTool) {
|
|
@@ -2480,11 +2531,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2480
2531
|
}
|
|
2481
2532
|
);
|
|
2482
2533
|
case "subtitle":
|
|
2483
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2534
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SubtitlesPanelContainer, {});
|
|
2484
2535
|
default:
|
|
2485
2536
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state-content", children: [
|
|
2486
2537
|
/* @__PURE__ */ jsxRuntime.jsx(WandSparkles, { className: "empty-state-icon" }),
|
|
2487
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Select
|
|
2538
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-text", children: "Select an element from toolbar" })
|
|
2488
2539
|
] }) }) });
|
|
2489
2540
|
}
|
|
2490
2541
|
};
|
|
@@ -3033,6 +3084,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3033
3084
|
if (!selectedElement) {
|
|
3034
3085
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "properties-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: "Select Element to see properties" }) }) });
|
|
3035
3086
|
}
|
|
3087
|
+
if (selectedElement.getType() === "caption") {
|
|
3088
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "panel-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "properties-header", children: /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "properties-title", children: "Not available for sub-title" }) }) });
|
|
3089
|
+
}
|
|
3036
3090
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3037
3091
|
selectedProp === "element-props" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3038
3092
|
ElementProps,
|