@nice2dev/ui-video 1.1.9 → 1.2.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.mjs CHANGED
@@ -1,6 +1,2176 @@
1
- import { N as r, a, b as c } from "./index-B5KCVHqL.js";
1
+ import { jsxs as t, jsx as e, Fragment as le } from "react/jsx-runtime";
2
+ import { NiceAppShell as he } from "@nice2dev/ui";
3
+ import { NiceIcon as u, NiceTutorialButton as pe, resolveTutorial as ve, createId as $ } from "@nice2dev/ui-core";
4
+ import { useState as b, useRef as M, useEffect as oe, useCallback as de } from "react";
5
+ const fe = {
6
+ id: $(),
7
+ name: "Untitled Project",
8
+ resolution: { width: 1920, height: 1080, label: "1080p" },
9
+ frameRate: 30,
10
+ duration: 0,
11
+ tracks: [
12
+ {
13
+ id: "1",
14
+ type: "video",
15
+ name: "Video 1",
16
+ items: [],
17
+ muted: !1,
18
+ locked: !1,
19
+ visible: !0
20
+ },
21
+ {
22
+ id: "2",
23
+ type: "audio",
24
+ name: "Audio 1",
25
+ items: [],
26
+ muted: !1,
27
+ locked: !1,
28
+ visible: !0
29
+ }
30
+ ],
31
+ assets: [],
32
+ settings: {
33
+ // Rendered into the exported video, where no --nice-* exists: literal.
34
+ backgroundColor: "#000000",
35
+ audio: { sampleRate: 48e3, channels: 2, bitrate: 320 },
36
+ video: { codec: "h264", bitrate: 8e3, profile: "high" }
37
+ }
38
+ }, be = [
39
+ { type: "blur", name: "Blur", icon: "droplet" },
40
+ { type: "brightness", name: "Brightness", icon: "sun" },
41
+ { type: "contrast", name: "Contrast", icon: "moon" },
42
+ { type: "saturation", name: "Saturation", icon: "palette" },
43
+ { type: "grayscale", name: "Grayscale", icon: "square" },
44
+ { type: "sepia", name: "Sepia", icon: "image" },
45
+ { type: "chromaKey", name: "Chroma Key", icon: "layers" },
46
+ { type: "crop", name: "Crop", icon: "crop" },
47
+ { type: "zoom", name: "Zoom", icon: "search" }
48
+ ], ge = [
49
+ { type: "fade", name: "Fade" },
50
+ { type: "dissolve", name: "Dissolve" },
51
+ { type: "wipe", name: "Wipe" },
52
+ { type: "slide", name: "Slide" },
53
+ { type: "zoom", name: "Zoom" },
54
+ { type: "push", name: "Push" }
55
+ ], Ne = [
56
+ {
57
+ target: ".nice-video-editor",
58
+ titleKey: "tutorial.videoEditorPro.intro.title",
59
+ title: "Video editor",
60
+ contentKey: "tutorial.videoEditorPro.intro.content",
61
+ content: "Add media to the timeline, arrange and trim clips, apply effects and transitions, then configure and run the export.",
62
+ placement: "auto"
63
+ }
64
+ ], ze = ({
65
+ project: R,
66
+ onProjectChange: z,
67
+ onExport: P,
68
+ onAssetUpload: F,
69
+ className: V = "",
70
+ tutorial: T
71
+ }) => {
72
+ const [d, s] = b(R || fe), [A, N] = b(
73
+ "timeline"
74
+ ), [H, h] = b(null), [k, y] = b(null), [D, w] = b(0), [O, B] = b(!1), [C, j] = b(1), [K, I] = b(!0), [_, L] = b(null), ee = M(null), ae = M(null), S = M(null);
75
+ oe(() => {
76
+ R && s(R);
77
+ }, [R]), oe(() => () => {
78
+ S.current && clearInterval(S.current);
79
+ }, []);
80
+ const g = de(
81
+ (n) => {
82
+ const l = { ...d, ...n };
83
+ s(l), z == null || z(l);
84
+ },
85
+ [d, z]
86
+ ), f = async (n) => {
87
+ const l = [];
88
+ for (const i of Array.from(n)) {
89
+ const c = i.type.startsWith("video/") ? "video" : i.type.startsWith("audio/") ? "audio" : "image";
90
+ let m;
91
+ F ? m = await F(i) : m = {
92
+ id: $(),
93
+ type: c,
94
+ name: i.name,
95
+ url: URL.createObjectURL(i),
96
+ size: i.size
97
+ }, l.push(m);
98
+ }
99
+ g({ assets: [...d.assets, ...l] });
100
+ }, U = (n) => {
101
+ const l = {
102
+ id: $(),
103
+ type: n,
104
+ name: `${n.charAt(0).toUpperCase() + n.slice(1)} ${d.tracks.filter((i) => i.type === n).length + 1}`,
105
+ items: [],
106
+ muted: !1,
107
+ locked: !1,
108
+ visible: !0
109
+ };
110
+ g({ tracks: [...d.tracks, l] });
111
+ }, G = (n) => {
112
+ g({ tracks: d.tracks.filter((l) => l.id !== n) }), H === n && h(null);
113
+ }, W = (n) => {
114
+ g({
115
+ tracks: d.tracks.map((l) => l.id === n ? { ...l, muted: !l.muted } : l)
116
+ });
117
+ }, Q = (n) => {
118
+ g({
119
+ tracks: d.tracks.map((l) => l.id === n ? { ...l, locked: !l.locked } : l)
120
+ });
121
+ }, x = (n, l) => {
122
+ const i = d.tracks.find((v) => v.id === n);
123
+ if (!i || i.locked)
124
+ return;
125
+ const c = i.items[i.items.length - 1], m = c ? c.startTime + c.duration : 0, p = {
126
+ id: $(),
127
+ assetId: l.id,
128
+ type: l.type,
129
+ startTime: m,
130
+ duration: l.duration || 5,
131
+ offset: 0,
132
+ properties: {
133
+ x: 0,
134
+ y: 0,
135
+ opacity: 1,
136
+ scale: 1,
137
+ volume: 1
138
+ },
139
+ effects: [],
140
+ transitions: []
141
+ };
142
+ g({
143
+ tracks: d.tracks.map(
144
+ (v) => v.id === n ? { ...v, items: [...v.items, p] } : v
145
+ )
146
+ });
147
+ }, Y = (n, l, i) => {
148
+ const c = {
149
+ id: $(),
150
+ type: i,
151
+ name: i.charAt(0).toUpperCase() + i.slice(1),
152
+ parameters: te(i)
153
+ };
154
+ g({
155
+ tracks: d.tracks.map(
156
+ (m) => m.id === n ? {
157
+ ...m,
158
+ items: m.items.map(
159
+ (p) => p.id === l ? { ...p, effects: [...p.effects, c] } : p
160
+ )
161
+ } : m
162
+ )
163
+ });
164
+ }, E = (n, l, i, c) => {
165
+ const m = {
166
+ id: $(),
167
+ type: i,
168
+ duration: 0.5,
169
+ position: c
170
+ };
171
+ g({
172
+ tracks: d.tracks.map(
173
+ (p) => p.id === n ? {
174
+ ...p,
175
+ items: p.items.map(
176
+ (v) => v.id === l ? { ...v, transitions: [...v.transitions, m] } : v
177
+ )
178
+ } : p
179
+ )
180
+ });
181
+ }, te = (n) => {
182
+ switch (n) {
183
+ case "blur":
184
+ return { radius: 5 };
185
+ case "brightness":
186
+ return { value: 100 };
187
+ case "contrast":
188
+ return { value: 100 };
189
+ case "saturation":
190
+ return { value: 100 };
191
+ case "grayscale":
192
+ return { amount: 100 };
193
+ case "sepia":
194
+ return { amount: 100 };
195
+ case "chromaKey":
196
+ return { color: "var(--nice-success, #00ff00)", threshold: 40 };
197
+ case "crop":
198
+ return { top: 0, right: 0, bottom: 0, left: 0 };
199
+ case "zoom":
200
+ return { scale: 1, x: 0, y: 0 };
201
+ default:
202
+ return {};
203
+ }
204
+ }, ie = () => {
205
+ O ? (S.current && clearInterval(S.current), B(!1)) : (S.current = setInterval(() => {
206
+ w((n) => {
207
+ const l = Math.max(
208
+ ...d.tracks.flatMap((i) => i.items.map((c) => c.startTime + c.duration)),
209
+ 0
210
+ );
211
+ return n >= l ? (clearInterval(S.current), B(!1), 0) : n + 1 / d.frameRate;
212
+ });
213
+ }, 1e3 / d.frameRate), B(!0));
214
+ }, Z = (n) => {
215
+ w(Math.max(0, n));
216
+ }, J = async () => {
217
+ if (P) {
218
+ L(0);
219
+ try {
220
+ const n = setInterval(() => {
221
+ L((l) => l !== null && l < 90 ? l + Math.random() * 10 : l);
222
+ }, 500);
223
+ await P(d, d.settings.video.codec), clearInterval(n), L(100), setTimeout(() => L(null), 2e3);
224
+ } catch (n) {
225
+ L(null), console.error("Export failed:", n);
226
+ }
227
+ }
228
+ }, X = (n) => {
229
+ const l = Math.floor(n / 60), i = Math.floor(n % 60), c = Math.floor(n % 1 * d.frameRate);
230
+ return `${l.toString().padStart(2, "0")}:${i.toString().padStart(2, "0")}:${c.toString().padStart(2, "0")}`;
231
+ }, q = () => {
232
+ for (const n of d.tracks) {
233
+ const l = n.items.find((i) => i.id === k);
234
+ if (l)
235
+ return { track: n, item: l };
236
+ }
237
+ return null;
238
+ }, ne = /* @__PURE__ */ t("header", { className: "video-editor__header", children: [
239
+ /* @__PURE__ */ t("div", { className: "header__project-info", children: [
240
+ /* @__PURE__ */ e(
241
+ "input",
242
+ {
243
+ type: "text",
244
+ value: d.name,
245
+ onChange: (n) => g({ name: n.target.value }),
246
+ className: "project-name-input"
247
+ }
248
+ ),
249
+ /* @__PURE__ */ t("span", { className: "project-settings", children: [
250
+ d.resolution.width,
251
+ "x",
252
+ d.resolution.height,
253
+ " • ",
254
+ d.frameRate,
255
+ "fps"
256
+ ] })
257
+ ] }),
258
+ /* @__PURE__ */ e("div", { className: "header__tabs", children: ["timeline", "effects", "transitions", "export"].map((n) => /* @__PURE__ */ e(
259
+ "button",
260
+ {
261
+ className: `tab-button ${A === n ? "tab-button--active" : ""}`,
262
+ onClick: () => N(n),
263
+ children: n.charAt(0).toUpperCase() + n.slice(1)
264
+ },
265
+ n
266
+ )) }),
267
+ /* @__PURE__ */ e("div", { className: "header__actions", children: /* @__PURE__ */ e(
268
+ "button",
269
+ {
270
+ className: "action-button action-button--primary",
271
+ onClick: J,
272
+ disabled: _ !== null,
273
+ children: _ !== null ? `Exporting ${Math.round(_)}%` : "Export"
274
+ }
275
+ ) })
276
+ ] }), se = k && A !== "export" ? (() => {
277
+ const n = q();
278
+ if (!n)
279
+ return null;
280
+ const { track: l, item: i } = n;
281
+ return /* @__PURE__ */ t("div", { className: "item-inspector", children: [
282
+ /* @__PURE__ */ e("h4", { children: "Item Properties" }),
283
+ /* @__PURE__ */ t("div", { className: "inspector-section", children: [
284
+ /* @__PURE__ */ t("label", { children: [
285
+ "Start Time",
286
+ /* @__PURE__ */ e(
287
+ "input",
288
+ {
289
+ type: "number",
290
+ step: "0.1",
291
+ value: i.startTime,
292
+ onChange: (c) => {
293
+ const m = parseFloat(c.target.value);
294
+ g({
295
+ tracks: d.tracks.map(
296
+ (p) => p.id === l.id ? {
297
+ ...p,
298
+ items: p.items.map(
299
+ (v) => v.id === i.id ? { ...v, startTime: m } : v
300
+ )
301
+ } : p
302
+ )
303
+ });
304
+ }
305
+ }
306
+ )
307
+ ] }),
308
+ /* @__PURE__ */ t("label", { children: [
309
+ "Duration",
310
+ /* @__PURE__ */ e(
311
+ "input",
312
+ {
313
+ type: "number",
314
+ step: "0.1",
315
+ value: i.duration,
316
+ onChange: (c) => {
317
+ const m = parseFloat(c.target.value);
318
+ g({
319
+ tracks: d.tracks.map(
320
+ (p) => p.id === l.id ? {
321
+ ...p,
322
+ items: p.items.map(
323
+ (v) => v.id === i.id ? { ...v, duration: m } : v
324
+ )
325
+ } : p
326
+ )
327
+ });
328
+ }
329
+ }
330
+ )
331
+ ] }),
332
+ /* @__PURE__ */ t("label", { children: [
333
+ "Opacity",
334
+ /* @__PURE__ */ e(
335
+ "input",
336
+ {
337
+ type: "range",
338
+ min: "0",
339
+ max: "1",
340
+ step: "0.1",
341
+ value: i.properties.opacity ?? 1,
342
+ onChange: (c) => {
343
+ const m = parseFloat(c.target.value);
344
+ g({
345
+ tracks: d.tracks.map(
346
+ (p) => p.id === l.id ? {
347
+ ...p,
348
+ items: p.items.map(
349
+ (v) => v.id === i.id ? {
350
+ ...v,
351
+ properties: { ...v.properties, opacity: m }
352
+ } : v
353
+ )
354
+ } : p
355
+ )
356
+ });
357
+ }
358
+ }
359
+ )
360
+ ] })
361
+ ] }),
362
+ /* @__PURE__ */ t("h4", { children: [
363
+ "Effects (",
364
+ i.effects.length,
365
+ ")"
366
+ ] }),
367
+ /* @__PURE__ */ e("div", { className: "effects-list", children: i.effects.map((c) => /* @__PURE__ */ e("div", { className: "effect-badge", children: c.name }, c.id)) })
368
+ ] });
369
+ })() : null, a = K ? /* @__PURE__ */ t("aside", { className: "video-editor__asset-library", children: [
370
+ /* @__PURE__ */ t("div", { className: "asset-library__header", children: [
371
+ /* @__PURE__ */ e("h3", { children: "Assets" }),
372
+ /* @__PURE__ */ e(
373
+ "button",
374
+ {
375
+ "aria-label": "Close",
376
+ className: "close-button",
377
+ onClick: () => I(!1),
378
+ children: /* @__PURE__ */ e(u, { name: "close", size: 16 })
379
+ }
380
+ )
381
+ ] }),
382
+ /* @__PURE__ */ e("div", { className: "asset-library__upload", children: /* @__PURE__ */ t("label", { className: "upload-zone", children: [
383
+ /* @__PURE__ */ e(
384
+ "input",
385
+ {
386
+ type: "file",
387
+ multiple: !0,
388
+ accept: "video/*,audio/*,image/*",
389
+ onChange: (n) => n.target.files && f(n.target.files),
390
+ hidden: !0
391
+ }
392
+ ),
393
+ /* @__PURE__ */ e("span", { className: "upload-icon", children: "+" }),
394
+ /* @__PURE__ */ e("span", { children: "Drop files or click to upload" })
395
+ ] }) }),
396
+ /* @__PURE__ */ e("div", { className: "asset-library__list", children: d.assets.map((n) => /* @__PURE__ */ t(
397
+ "div",
398
+ {
399
+ className: "asset-item",
400
+ draggable: !0,
401
+ onDragStart: (l) => l.dataTransfer.setData("assetId", n.id),
402
+ children: [
403
+ /* @__PURE__ */ e("div", { className: "asset-thumbnail", children: n.thumbnail ? /* @__PURE__ */ e("img", { src: n.thumbnail, alt: n.name }) : /* @__PURE__ */ e("span", { className: "asset-type-icon", children: /* @__PURE__ */ e(
404
+ u,
405
+ {
406
+ name: n.type === "video" ? "video" : n.type === "audio" ? "music" : "image",
407
+ size: 24
408
+ }
409
+ ) }) }),
410
+ /* @__PURE__ */ t("div", { className: "asset-info", children: [
411
+ /* @__PURE__ */ e("span", { className: "asset-name", children: n.name }),
412
+ /* @__PURE__ */ t("span", { className: "asset-meta", children: [
413
+ (n.size / 1024 / 1024).toFixed(1),
414
+ "MB"
415
+ ] })
416
+ ] })
417
+ ]
418
+ },
419
+ n.id
420
+ )) })
421
+ ] }) : void 0, r = /* @__PURE__ */ e("div", { className: "video-editor__preview-area", children: /* @__PURE__ */ t("div", { className: "preview-container", children: [
422
+ /* @__PURE__ */ t(
423
+ "div",
424
+ {
425
+ className: "preview-canvas",
426
+ style: { aspectRatio: `${d.resolution.width}/${d.resolution.height}` },
427
+ children: [
428
+ /* @__PURE__ */ e("video", { ref: ae, className: "preview-video" }),
429
+ /* @__PURE__ */ e("div", { className: "preview-overlay", children: !K && /* @__PURE__ */ e(
430
+ "button",
431
+ {
432
+ className: "toggle-library-button",
433
+ onClick: () => I(!0),
434
+ "aria-label": "Show asset library",
435
+ children: /* @__PURE__ */ e(u, { name: "folder", size: 16 })
436
+ }
437
+ ) })
438
+ ]
439
+ }
440
+ ),
441
+ /* @__PURE__ */ t("div", { className: "playback-controls", children: [
442
+ /* @__PURE__ */ e("button", { onClick: () => Z(0), "aria-label": "Go to start", children: /* @__PURE__ */ e(u, { name: "skip-back", size: 16 }) }),
443
+ /* @__PURE__ */ e(
444
+ "button",
445
+ {
446
+ onClick: () => Z(D - 1 / d.frameRate),
447
+ "aria-label": "Previous frame",
448
+ children: /* @__PURE__ */ e(u, { name: "chevron-left", size: 16 })
449
+ }
450
+ ),
451
+ /* @__PURE__ */ e(
452
+ "button",
453
+ {
454
+ onClick: ie,
455
+ className: "play-button",
456
+ "aria-label": O ? "Pause" : "Play",
457
+ children: /* @__PURE__ */ e(u, { name: O ? "pause" : "play", size: 18 })
458
+ }
459
+ ),
460
+ /* @__PURE__ */ e(
461
+ "button",
462
+ {
463
+ onClick: () => Z(D + 1 / d.frameRate),
464
+ "aria-label": "Next frame",
465
+ children: /* @__PURE__ */ e(u, { name: "chevron-right", size: 16 })
466
+ }
467
+ ),
468
+ /* @__PURE__ */ e("span", { className: "time-display", children: X(D) })
469
+ ] })
470
+ ] }) }), o = /* @__PURE__ */ t("div", { className: "video-editor__panel", children: [
471
+ A === "timeline" && /* @__PURE__ */ t("div", { className: "timeline-panel", children: [
472
+ /* @__PURE__ */ t("div", { className: "timeline-toolbar", children: [
473
+ /* @__PURE__ */ t("div", { className: "track-buttons", children: [
474
+ /* @__PURE__ */ e("button", { onClick: () => U("video"), children: "+ Video Track" }),
475
+ /* @__PURE__ */ e("button", { onClick: () => U("audio"), children: "+ Audio Track" }),
476
+ /* @__PURE__ */ e("button", { onClick: () => U("text"), children: "+ Text Track" })
477
+ ] }),
478
+ /* @__PURE__ */ t("div", { className: "zoom-controls", children: [
479
+ /* @__PURE__ */ e("button", { onClick: () => j(Math.max(0.25, C - 0.25)), children: "-" }),
480
+ /* @__PURE__ */ t("span", { children: [
481
+ Math.round(C * 100),
482
+ "%"
483
+ ] }),
484
+ /* @__PURE__ */ e("button", { onClick: () => j(Math.min(4, C + 0.25)), children: "+" })
485
+ ] })
486
+ ] }),
487
+ /* @__PURE__ */ t("div", { className: "timeline-container", ref: ee, children: [
488
+ /* @__PURE__ */ e("div", { className: "timeline-ruler", children: Array.from({ length: Math.ceil(30 / C) }).map((n, l) => /* @__PURE__ */ e("div", { className: "ruler-mark", style: { left: `${l * 50 * C}px` }, children: X(l) }, l)) }),
489
+ /* @__PURE__ */ e("div", { className: "timeline-playhead", style: { left: `${D * 50 * C}px` } }),
490
+ /* @__PURE__ */ e("div", { className: "timeline-tracks", children: d.tracks.map((n) => /* @__PURE__ */ t(
491
+ "div",
492
+ {
493
+ className: `timeline-track ${H === n.id ? "timeline-track--selected" : ""} ${n.locked ? "timeline-track--locked" : ""}`,
494
+ onClick: () => h(n.id),
495
+ onDrop: (l) => {
496
+ l.preventDefault();
497
+ const i = l.dataTransfer.getData("assetId"), c = d.assets.find((m) => m.id === i);
498
+ c && x(n.id, c);
499
+ },
500
+ onDragOver: (l) => l.preventDefault(),
501
+ children: [
502
+ /* @__PURE__ */ t("div", { className: "track-header", children: [
503
+ /* @__PURE__ */ e("span", { className: "track-name", children: n.name }),
504
+ /* @__PURE__ */ t("div", { className: "track-controls", children: [
505
+ /* @__PURE__ */ e(
506
+ "button",
507
+ {
508
+ className: n.muted ? "active" : "",
509
+ onClick: (l) => {
510
+ l.stopPropagation(), W(n.id);
511
+ },
512
+ children: /* @__PURE__ */ e(u, { name: n.muted ? "volume-off" : "volume", size: 14 })
513
+ }
514
+ ),
515
+ /* @__PURE__ */ e(
516
+ "button",
517
+ {
518
+ className: n.locked ? "active" : "",
519
+ onClick: (l) => {
520
+ l.stopPropagation(), Q(n.id);
521
+ },
522
+ children: /* @__PURE__ */ e(u, { name: n.locked ? "lock" : "unlock", size: 14 })
523
+ }
524
+ ),
525
+ /* @__PURE__ */ e(
526
+ "button",
527
+ {
528
+ onClick: (l) => {
529
+ l.stopPropagation(), G(n.id);
530
+ },
531
+ "aria-label": "Remove track",
532
+ children: /* @__PURE__ */ e(u, { name: "trash", size: 14 })
533
+ }
534
+ )
535
+ ] })
536
+ ] }),
537
+ /* @__PURE__ */ e("div", { className: "track-items", children: n.items.map((l) => {
538
+ const i = d.assets.find((c) => c.id === l.assetId);
539
+ return /* @__PURE__ */ t(
540
+ "div",
541
+ {
542
+ className: `track-item track-item--${l.type} ${k === l.id ? "track-item--selected" : ""}`,
543
+ style: {
544
+ left: `${l.startTime * 50 * C}px`,
545
+ width: `${l.duration * 50 * C}px`
546
+ },
547
+ onClick: (c) => {
548
+ c.stopPropagation(), y(l.id);
549
+ },
550
+ children: [
551
+ /* @__PURE__ */ e("span", { className: "item-name", children: (i == null ? void 0 : i.name) || "Untitled" }),
552
+ l.transitions.length > 0 && /* @__PURE__ */ e("span", { className: "item-transitions", children: /* @__PURE__ */ e(u, { name: "wand", size: 12 }) }),
553
+ l.effects.length > 0 && /* @__PURE__ */ e("span", { className: "item-effects", children: /* @__PURE__ */ e(u, { name: "palette", size: 12 }) })
554
+ ]
555
+ },
556
+ l.id
557
+ );
558
+ }) })
559
+ ]
560
+ },
561
+ n.id
562
+ )) })
563
+ ] })
564
+ ] }),
565
+ A === "effects" && /* @__PURE__ */ t("div", { className: "effects-panel", children: [
566
+ /* @__PURE__ */ e("h3", { children: "Video Effects" }),
567
+ /* @__PURE__ */ e("p", { className: "panel-hint", children: "Select a clip to apply effects" }),
568
+ /* @__PURE__ */ e("div", { className: "effects-grid", children: be.map((n) => /* @__PURE__ */ t(
569
+ "button",
570
+ {
571
+ className: "effect-preset",
572
+ disabled: !k,
573
+ onClick: () => {
574
+ const l = q();
575
+ l && Y(l.track.id, l.item.id, n.type);
576
+ },
577
+ children: [
578
+ /* @__PURE__ */ e("span", { className: "effect-icon", children: /* @__PURE__ */ e(u, { name: n.icon, size: 16 }) }),
579
+ /* @__PURE__ */ e("span", { className: "effect-name", children: n.name })
580
+ ]
581
+ },
582
+ n.type
583
+ )) })
584
+ ] }),
585
+ A === "transitions" && /* @__PURE__ */ t("div", { className: "transitions-panel", children: [
586
+ /* @__PURE__ */ e("h3", { children: "Transitions" }),
587
+ /* @__PURE__ */ e("p", { className: "panel-hint", children: "Select a clip and add transitions between clips" }),
588
+ /* @__PURE__ */ e("div", { className: "transitions-grid", children: ge.map((n) => /* @__PURE__ */ t("div", { className: "transition-preset", children: [
589
+ /* @__PURE__ */ e("span", { className: "transition-name", children: n.name }),
590
+ /* @__PURE__ */ t("div", { className: "transition-buttons", children: [
591
+ /* @__PURE__ */ e(
592
+ "button",
593
+ {
594
+ disabled: !k,
595
+ onClick: () => {
596
+ const l = q();
597
+ l && E(l.track.id, l.item.id, n.type, "start");
598
+ },
599
+ children: "In"
600
+ }
601
+ ),
602
+ /* @__PURE__ */ e(
603
+ "button",
604
+ {
605
+ disabled: !k,
606
+ onClick: () => {
607
+ const l = q();
608
+ l && E(l.track.id, l.item.id, n.type, "end");
609
+ },
610
+ children: "Out"
611
+ }
612
+ )
613
+ ] })
614
+ ] }, n.type)) })
615
+ ] }),
616
+ A === "export" && /* @__PURE__ */ t("div", { className: "export-panel", children: [
617
+ /* @__PURE__ */ e("h3", { children: "Export Settings" }),
618
+ /* @__PURE__ */ t("div", { className: "export-settings", children: [
619
+ /* @__PURE__ */ t("div", { className: "setting-group", children: [
620
+ /* @__PURE__ */ e("label", { children: "Resolution" }),
621
+ /* @__PURE__ */ t(
622
+ "select",
623
+ {
624
+ value: `${d.resolution.width}x${d.resolution.height}`,
625
+ onChange: (n) => {
626
+ const [l, i] = n.target.value.split("x").map(Number);
627
+ g({ resolution: { width: l, height: i } });
628
+ },
629
+ children: [
630
+ /* @__PURE__ */ e("option", { value: "1920x1080", children: "1080p (1920x1080)" }),
631
+ /* @__PURE__ */ e("option", { value: "2560x1440", children: "1440p (2560x1440)" }),
632
+ /* @__PURE__ */ e("option", { value: "3840x2160", children: "4K (3840x2160)" }),
633
+ /* @__PURE__ */ e("option", { value: "1280x720", children: "720p (1280x720)" })
634
+ ]
635
+ }
636
+ )
637
+ ] }),
638
+ /* @__PURE__ */ t("div", { className: "setting-group", children: [
639
+ /* @__PURE__ */ e("label", { children: "Frame Rate" }),
640
+ /* @__PURE__ */ t(
641
+ "select",
642
+ {
643
+ value: d.frameRate,
644
+ onChange: (n) => g({ frameRate: parseInt(n.target.value) }),
645
+ children: [
646
+ /* @__PURE__ */ e("option", { value: "24", children: "24 fps" }),
647
+ /* @__PURE__ */ e("option", { value: "30", children: "30 fps" }),
648
+ /* @__PURE__ */ e("option", { value: "60", children: "60 fps" }),
649
+ /* @__PURE__ */ e("option", { value: "120", children: "120 fps" })
650
+ ]
651
+ }
652
+ )
653
+ ] }),
654
+ /* @__PURE__ */ t("div", { className: "setting-group", children: [
655
+ /* @__PURE__ */ e("label", { children: "Video Codec" }),
656
+ /* @__PURE__ */ t(
657
+ "select",
658
+ {
659
+ value: d.settings.video.codec,
660
+ onChange: (n) => g({
661
+ settings: {
662
+ ...d.settings,
663
+ video: {
664
+ ...d.settings.video,
665
+ codec: n.target.value
666
+ }
667
+ }
668
+ }),
669
+ children: [
670
+ /* @__PURE__ */ e("option", { value: "h264", children: "H.264 (Best Compatibility)" }),
671
+ /* @__PURE__ */ e("option", { value: "h265", children: "H.265/HEVC (Smaller Size)" }),
672
+ /* @__PURE__ */ e("option", { value: "vp9", children: "VP9 (Web Optimized)" }),
673
+ /* @__PURE__ */ e("option", { value: "av1", children: "AV1 (Future Standard)" })
674
+ ]
675
+ }
676
+ )
677
+ ] }),
678
+ /* @__PURE__ */ t("div", { className: "setting-group", children: [
679
+ /* @__PURE__ */ e("label", { children: "Video Bitrate (Mbps)" }),
680
+ /* @__PURE__ */ e(
681
+ "input",
682
+ {
683
+ type: "number",
684
+ value: d.settings.video.bitrate / 1e3,
685
+ onChange: (n) => g({
686
+ settings: {
687
+ ...d.settings,
688
+ video: {
689
+ ...d.settings.video,
690
+ bitrate: parseFloat(n.target.value) * 1e3
691
+ }
692
+ }
693
+ }),
694
+ min: "1",
695
+ max: "100"
696
+ }
697
+ )
698
+ ] })
699
+ ] }),
700
+ /* @__PURE__ */ e(
701
+ "button",
702
+ {
703
+ className: "export-button",
704
+ onClick: J,
705
+ disabled: _ !== null,
706
+ children: _ !== null ? `Exporting... ${Math.round(_)}%` : "Export Video"
707
+ }
708
+ ),
709
+ _ !== null && /* @__PURE__ */ e("div", { className: "export-progress", children: /* @__PURE__ */ e("div", { className: "export-progress-bar", style: { width: `${_}%` } }) })
710
+ ] })
711
+ ] });
712
+ return /* @__PURE__ */ t(
713
+ he,
714
+ {
715
+ flush: !0,
716
+ className: `nice-video-editor ${V}`,
717
+ height: "100%",
718
+ style: { position: "relative", minHeight: 600 },
719
+ toolbar: ne,
720
+ sidebar: a,
721
+ rightSidebar: se ?? void 0,
722
+ bottomPanel: o,
723
+ children: [
724
+ /* @__PURE__ */ e("span", { style: { position: "absolute", top: 6, right: 6, zIndex: 30 }, children: /* @__PURE__ */ e(pe, { steps: ve(T, Ne) }) }),
725
+ r
726
+ ]
727
+ }
728
+ );
729
+ }, ye = {
730
+ video: {
731
+ source: "screen",
732
+ showCursor: !0,
733
+ frameRate: 30,
734
+ resolution: { width: 1920, height: 1080 }
735
+ },
736
+ audio: {
737
+ enabled: !0,
738
+ source: "both",
739
+ echoCancellation: !0,
740
+ noiseSuppression: !0
741
+ },
742
+ output: {
743
+ format: "webm",
744
+ quality: "high"
745
+ }
746
+ }, Ie = ({
747
+ options: R,
748
+ onRecordingStart: z,
749
+ onRecordingStop: P,
750
+ onRecordingPause: F,
751
+ onRecordingResume: V,
752
+ onError: T,
753
+ className: d = ""
754
+ }) => {
755
+ var n, l;
756
+ const [s, A] = b({
757
+ ...ye,
758
+ ...R
759
+ }), [N, H] = b(null), [h, k] = b("idle"), [y, D] = b([]), [w, O] = b(null), [B, C] = b(null), [j, K] = b(!1), [I, _] = b(!1), [L, ee] = b(
760
+ "pen"
761
+ ), [ae, S] = b("var(--nice-danger, #ff0000)"), g = M(null), f = M([]), U = M(null), G = M(null), W = M(null), Q = M(0);
762
+ oe(() => () => {
763
+ w && w.getTracks().forEach((i) => i.stop()), W.current && clearInterval(W.current);
764
+ }, [w]);
765
+ const x = (i) => {
766
+ A((c) => ({
767
+ ...c,
768
+ ...i,
769
+ video: { ...c.video, ...i.video },
770
+ audio: { ...c.audio, ...i.audio },
771
+ output: { ...c.output, ...i.output }
772
+ }));
773
+ }, Y = async () => {
774
+ try {
775
+ k("preparing");
776
+ const i = {
777
+ video: {
778
+ cursor: s.video.showCursor ? "always" : "never",
779
+ frameRate: s.video.frameRate
780
+ },
781
+ audio: s.audio.source === "system" || s.audio.source === "both"
782
+ }, c = await navigator.mediaDevices.getDisplayMedia(i);
783
+ if (s.audio.enabled && (s.audio.source === "microphone" || s.audio.source === "both"))
784
+ try {
785
+ (await navigator.mediaDevices.getUserMedia({
786
+ audio: {
787
+ echoCancellation: s.audio.echoCancellation,
788
+ noiseSuppression: s.audio.noiseSuppression
789
+ }
790
+ })).getAudioTracks().forEach((p) => c.addTrack(p));
791
+ } catch (m) {
792
+ console.warn("Could not access microphone:", m);
793
+ }
794
+ O(c), U.current && (U.current.srcObject = c, U.current.play()), k("idle");
795
+ } catch (i) {
796
+ k("error"), T == null || T(i instanceof Error ? i : new Error("Failed to start preview"));
797
+ }
798
+ }, E = async () => {
799
+ w || await Y();
800
+ for (let i = 3; i > 0; i--)
801
+ C(i), await new Promise((c) => setTimeout(c, 1e3));
802
+ C(null);
803
+ try {
804
+ const i = w || await te();
805
+ if (!i)
806
+ throw new Error("No stream available");
807
+ const c = ne(s.output.format), m = new MediaRecorder(i, {
808
+ mimeType: c,
809
+ videoBitsPerSecond: se(s.output.quality)
810
+ });
811
+ f.current = [], m.ondataavailable = (v) => {
812
+ v.data.size > 0 && f.current.push(v.data);
813
+ }, m.onstop = () => {
814
+ const v = new Blob(f.current, { type: c });
815
+ N && (P == null || P({ ...N, status: "stopped" }, v));
816
+ }, g.current = m, m.start(1e3), Q.current = Date.now();
817
+ const p = {
818
+ id: $(),
819
+ status: "recording",
820
+ startTime: /* @__PURE__ */ new Date(),
821
+ duration: 0,
822
+ size: 0,
823
+ options: s,
824
+ chunks: []
825
+ };
826
+ H(p), k("recording"), z == null || z(p), W.current = setInterval(() => {
827
+ H(
828
+ (v) => v ? {
829
+ ...v,
830
+ duration: (Date.now() - Q.current) / 1e3,
831
+ size: f.current.reduce((ue, me) => ue + me.size, 0)
832
+ } : null
833
+ );
834
+ }, 100);
835
+ } catch (i) {
836
+ k("error"), T == null || T(i instanceof Error ? i : new Error("Failed to start recording"));
837
+ }
838
+ }, te = async () => (await Y(), w), ie = () => {
839
+ g.current && h === "recording" && (g.current.pause(), k("paused"), F == null || F());
840
+ }, Z = () => {
841
+ g.current && h === "paused" && (g.current.resume(), k("recording"), V == null || V());
842
+ }, J = () => {
843
+ W.current && clearInterval(W.current), g.current && (h === "recording" || h === "paused") && (g.current.stop(), k("stopped")), w && (w.getTracks().forEach((i) => i.stop()), O(null));
844
+ }, X = de(
845
+ (i) => {
846
+ if (h !== "recording")
847
+ return;
848
+ const c = {
849
+ id: $(),
850
+ time: (N == null ? void 0 : N.duration) || 0,
851
+ label: i || `Marker ${y.length + 1}`,
852
+ color: a()
853
+ };
854
+ D((m) => [...m, c]);
855
+ },
856
+ [h, N == null ? void 0 : N.duration, y.length]
857
+ ), q = (i) => {
858
+ D((c) => c.filter((m) => m.id !== i));
859
+ }, ne = (i) => {
860
+ switch (i) {
861
+ case "mp4":
862
+ return "video/mp4";
863
+ case "mkv":
864
+ return "video/x-matroska";
865
+ default:
866
+ return "video/webm;codecs=vp9";
867
+ }
868
+ }, se = (i) => {
869
+ switch (i) {
870
+ case "low":
871
+ return 25e5;
872
+ case "medium":
873
+ return 5e6;
874
+ case "lossless":
875
+ return 2e7;
876
+ default:
877
+ return 8e6;
878
+ }
879
+ }, a = () => {
880
+ const i = [
881
+ "var(--nice-danger, #ff4444)",
882
+ "#44ff44",
883
+ "#4444ff",
884
+ "#ffff44",
885
+ "#ff44ff",
886
+ "#44ffff"
887
+ ];
888
+ return i[Math.floor(Math.random() * i.length)];
889
+ }, r = (i) => {
890
+ const c = Math.floor(i / 3600), m = Math.floor(i % 3600 / 60), p = Math.floor(i % 60), v = Math.floor(i % 1 * 100);
891
+ return c > 0 ? `${c}:${m.toString().padStart(2, "0")}:${p.toString().padStart(2, "0")}` : `${m.toString().padStart(2, "0")}:${p.toString().padStart(2, "0")}.${v.toString().padStart(2, "0")}`;
892
+ }, o = (i) => i < 1024 ? `${i} B` : i < 1024 * 1024 ? `${(i / 1024).toFixed(1)} KB` : `${(i / 1024 / 1024).toFixed(1)} MB`;
893
+ return /* @__PURE__ */ t("div", { className: `nice-screen-recorder ${d}`, children: [
894
+ /* @__PURE__ */ t("div", { className: "recorder__preview", children: [
895
+ B !== null && /* @__PURE__ */ e("div", { className: "countdown-overlay", children: /* @__PURE__ */ e("span", { className: "countdown-number", children: B }) }),
896
+ /* @__PURE__ */ e("video", { ref: U, className: "preview-video", muted: !0, playsInline: !0 }),
897
+ I && /* @__PURE__ */ e("canvas", { ref: G, className: "annotation-canvas" }),
898
+ !w && h === "idle" && /* @__PURE__ */ e("div", { className: "preview-placeholder", children: /* @__PURE__ */ t("button", { className: "start-preview-button", onClick: Y, children: [
899
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "monitor", size: 18 }) }),
900
+ /* @__PURE__ */ e("span", { children: "Select Screen to Record" })
901
+ ] }) }),
902
+ h === "recording" && /* @__PURE__ */ t("div", { className: "recording-indicator", children: [
903
+ /* @__PURE__ */ e("span", { className: "recording-dot" }),
904
+ /* @__PURE__ */ e("span", { children: "REC" })
905
+ ] })
906
+ ] }),
907
+ /* @__PURE__ */ t("div", { className: "recorder__controls", children: [
908
+ /* @__PURE__ */ t("div", { className: "controls__main", children: [
909
+ h === "idle" && /* @__PURE__ */ t(
910
+ "button",
911
+ {
912
+ className: "control-button control-button--record",
913
+ onClick: E,
914
+ disabled: !!B,
915
+ children: [
916
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "circle", size: 18 }) }),
917
+ /* @__PURE__ */ e("span", { children: "Start Recording" })
918
+ ]
919
+ }
920
+ ),
921
+ h === "recording" && /* @__PURE__ */ t(le, { children: [
922
+ /* @__PURE__ */ t("button", { className: "control-button control-button--pause", onClick: ie, children: [
923
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "pause", size: 18 }) }),
924
+ /* @__PURE__ */ e("span", { children: "Pause" })
925
+ ] }),
926
+ /* @__PURE__ */ t("button", { className: "control-button control-button--stop", onClick: J, children: [
927
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "stop", size: 18 }) }),
928
+ /* @__PURE__ */ e("span", { children: "Stop" })
929
+ ] })
930
+ ] }),
931
+ h === "paused" && /* @__PURE__ */ t(le, { children: [
932
+ /* @__PURE__ */ t("button", { className: "control-button control-button--resume", onClick: Z, children: [
933
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "play", size: 18 }) }),
934
+ /* @__PURE__ */ e("span", { children: "Resume" })
935
+ ] }),
936
+ /* @__PURE__ */ t("button", { className: "control-button control-button--stop", onClick: J, children: [
937
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "stop", size: 18 }) }),
938
+ /* @__PURE__ */ e("span", { children: "Stop" })
939
+ ] })
940
+ ] }),
941
+ h === "stopped" && /* @__PURE__ */ t(
942
+ "button",
943
+ {
944
+ className: "control-button control-button--new",
945
+ onClick: () => {
946
+ k("idle"), H(null), D([]);
947
+ },
948
+ children: [
949
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "refresh", size: 18 }) }),
950
+ /* @__PURE__ */ e("span", { children: "New Recording" })
951
+ ]
952
+ }
953
+ )
954
+ ] }),
955
+ /* @__PURE__ */ t("div", { className: "controls__secondary", children: [
956
+ (h === "recording" || h === "paused") && /* @__PURE__ */ t("button", { className: "control-button control-button--marker", onClick: () => X(), children: [
957
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "tag", size: 18 }) }),
958
+ /* @__PURE__ */ e("span", { children: "Add Marker" })
959
+ ] }),
960
+ /* @__PURE__ */ t(
961
+ "button",
962
+ {
963
+ className: `control-button ${I ? "control-button--active" : ""}`,
964
+ onClick: () => _(!I),
965
+ disabled: h !== "recording",
966
+ children: [
967
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "pen", size: 18 }) }),
968
+ /* @__PURE__ */ e("span", { children: "Annotate" })
969
+ ]
970
+ }
971
+ ),
972
+ /* @__PURE__ */ e(
973
+ "button",
974
+ {
975
+ className: "control-button control-button--settings",
976
+ onClick: () => K(!j),
977
+ disabled: h === "recording",
978
+ "aria-label": "Settings",
979
+ children: /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: "settings", size: 18 }) })
980
+ }
981
+ )
982
+ ] })
983
+ ] }),
984
+ /* @__PURE__ */ t("div", { className: "recorder__status", children: [
985
+ /* @__PURE__ */ t("div", { className: "status__info", children: [
986
+ /* @__PURE__ */ t("span", { className: "status-item", children: [
987
+ /* @__PURE__ */ e("strong", { children: "Duration:" }),
988
+ " ",
989
+ r((N == null ? void 0 : N.duration) || 0)
990
+ ] }),
991
+ /* @__PURE__ */ t("span", { className: "status-item", children: [
992
+ /* @__PURE__ */ e("strong", { children: "Size:" }),
993
+ " ",
994
+ o((N == null ? void 0 : N.size) || 0)
995
+ ] }),
996
+ /* @__PURE__ */ t("span", { className: "status-item", children: [
997
+ /* @__PURE__ */ e("strong", { children: "Markers:" }),
998
+ " ",
999
+ y.length
1000
+ ] })
1001
+ ] }),
1002
+ /* @__PURE__ */ t("div", { className: "status__quality", children: [
1003
+ s.video.resolution && /* @__PURE__ */ t("span", { children: [
1004
+ s.video.resolution.width,
1005
+ "x",
1006
+ s.video.resolution.height
1007
+ ] }),
1008
+ /* @__PURE__ */ t("span", { children: [
1009
+ s.video.frameRate,
1010
+ "fps"
1011
+ ] }),
1012
+ /* @__PURE__ */ e("span", { className: s.audio.enabled ? "audio-on" : "audio-off", children: /* @__PURE__ */ e(u, { name: s.audio.enabled ? "volume" : "volume-off", size: 14 }) })
1013
+ ] })
1014
+ ] }),
1015
+ I && h === "recording" && /* @__PURE__ */ t("div", { className: "recorder__annotation-tools", children: [
1016
+ /* @__PURE__ */ e("div", { className: "tool-group", children: ["pen", "arrow", "rectangle", "text"].map((i) => /* @__PURE__ */ e(
1017
+ "button",
1018
+ {
1019
+ className: `tool-button ${L === i ? "tool-button--active" : ""}`,
1020
+ onClick: () => ee(i),
1021
+ "aria-label": i,
1022
+ children: /* @__PURE__ */ e(
1023
+ u,
1024
+ {
1025
+ name: i === "pen" ? "pen" : i === "arrow" ? "arrow-right" : i === "rectangle" ? "square" : "type",
1026
+ size: 16
1027
+ }
1028
+ )
1029
+ },
1030
+ i
1031
+ )) }),
1032
+ /* @__PURE__ */ e("div", { className: "color-group", children: [
1033
+ "var(--nice-danger, #ff0000)",
1034
+ "var(--nice-success, #00ff00)",
1035
+ "var(--nice-primary, #0000ff)",
1036
+ "var(--nice-warning, #ffff00)",
1037
+ "var(--nice-bg, #fff)",
1038
+ "var(--nice-text, #000000)"
1039
+ ].map((i) => /* @__PURE__ */ e(
1040
+ "button",
1041
+ {
1042
+ className: `color-button ${ae === i ? "color-button--active" : ""}`,
1043
+ style: { backgroundColor: i },
1044
+ onClick: () => S(i)
1045
+ },
1046
+ i
1047
+ )) })
1048
+ ] }),
1049
+ y.length > 0 && /* @__PURE__ */ t("div", { className: "recorder__markers", children: [
1050
+ /* @__PURE__ */ e("h4", { children: "Markers" }),
1051
+ /* @__PURE__ */ e("div", { className: "markers-list", children: y.map((i) => /* @__PURE__ */ t(
1052
+ "div",
1053
+ {
1054
+ className: "marker-item",
1055
+ style: { borderLeftColor: i.color },
1056
+ children: [
1057
+ /* @__PURE__ */ e("span", { className: "marker-time", children: r(i.time) }),
1058
+ /* @__PURE__ */ e(
1059
+ "input",
1060
+ {
1061
+ type: "text",
1062
+ value: i.label,
1063
+ onChange: (c) => {
1064
+ D(
1065
+ (m) => m.map((p) => p.id === i.id ? { ...p, label: c.target.value } : p)
1066
+ );
1067
+ },
1068
+ className: "marker-label"
1069
+ }
1070
+ ),
1071
+ /* @__PURE__ */ e(
1072
+ "button",
1073
+ {
1074
+ "aria-label": "Close",
1075
+ className: "marker-remove",
1076
+ onClick: () => q(i.id),
1077
+ children: /* @__PURE__ */ e(u, { name: "close", size: 16 })
1078
+ }
1079
+ )
1080
+ ]
1081
+ },
1082
+ i.id
1083
+ )) })
1084
+ ] }),
1085
+ j && /* @__PURE__ */ t("div", { className: "recorder__settings", children: [
1086
+ /* @__PURE__ */ t("div", { className: "settings-header", children: [
1087
+ /* @__PURE__ */ e("h3", { children: "Recording Settings" }),
1088
+ /* @__PURE__ */ e(
1089
+ "button",
1090
+ {
1091
+ "aria-label": "Close",
1092
+ className: "close-button",
1093
+ onClick: () => K(!1),
1094
+ children: /* @__PURE__ */ e(u, { name: "close", size: 16 })
1095
+ }
1096
+ )
1097
+ ] }),
1098
+ /* @__PURE__ */ t("div", { className: "settings-section", children: [
1099
+ /* @__PURE__ */ e("h4", { children: "Video" }),
1100
+ /* @__PURE__ */ t("label", { children: [
1101
+ "Source",
1102
+ /* @__PURE__ */ t(
1103
+ "select",
1104
+ {
1105
+ value: s.video.source,
1106
+ onChange: (i) => x({
1107
+ video: {
1108
+ ...s.video,
1109
+ source: i.target.value
1110
+ }
1111
+ }),
1112
+ children: [
1113
+ /* @__PURE__ */ e("option", { value: "screen", children: "Entire Screen" }),
1114
+ /* @__PURE__ */ e("option", { value: "window", children: "Application Window" }),
1115
+ /* @__PURE__ */ e("option", { value: "tab", children: "Browser Tab" }),
1116
+ /* @__PURE__ */ e("option", { value: "camera", children: "Camera" })
1117
+ ]
1118
+ }
1119
+ )
1120
+ ] }),
1121
+ /* @__PURE__ */ t("label", { children: [
1122
+ "Resolution",
1123
+ /* @__PURE__ */ t(
1124
+ "select",
1125
+ {
1126
+ value: `${(n = s.video.resolution) == null ? void 0 : n.width}x${(l = s.video.resolution) == null ? void 0 : l.height}`,
1127
+ onChange: (i) => {
1128
+ const [c, m] = i.target.value.split("x").map(Number);
1129
+ x({
1130
+ video: { ...s.video, resolution: { width: c, height: m } }
1131
+ });
1132
+ },
1133
+ children: [
1134
+ /* @__PURE__ */ e("option", { value: "1920x1080", children: "1080p (1920x1080)" }),
1135
+ /* @__PURE__ */ e("option", { value: "2560x1440", children: "1440p (2560x1440)" }),
1136
+ /* @__PURE__ */ e("option", { value: "3840x2160", children: "4K (3840x2160)" }),
1137
+ /* @__PURE__ */ e("option", { value: "1280x720", children: "720p (1280x720)" })
1138
+ ]
1139
+ }
1140
+ )
1141
+ ] }),
1142
+ /* @__PURE__ */ t("label", { children: [
1143
+ "Frame Rate",
1144
+ /* @__PURE__ */ t(
1145
+ "select",
1146
+ {
1147
+ value: s.video.frameRate,
1148
+ onChange: (i) => x({
1149
+ video: { ...s.video, frameRate: parseInt(i.target.value) }
1150
+ }),
1151
+ children: [
1152
+ /* @__PURE__ */ e("option", { value: "15", children: "15 fps" }),
1153
+ /* @__PURE__ */ e("option", { value: "24", children: "24 fps" }),
1154
+ /* @__PURE__ */ e("option", { value: "30", children: "30 fps" }),
1155
+ /* @__PURE__ */ e("option", { value: "60", children: "60 fps" })
1156
+ ]
1157
+ }
1158
+ )
1159
+ ] }),
1160
+ /* @__PURE__ */ t("label", { className: "checkbox-label", children: [
1161
+ /* @__PURE__ */ e(
1162
+ "input",
1163
+ {
1164
+ type: "checkbox",
1165
+ checked: s.video.showCursor,
1166
+ onChange: (i) => x({
1167
+ video: { ...s.video, showCursor: i.target.checked }
1168
+ })
1169
+ }
1170
+ ),
1171
+ "Show Cursor"
1172
+ ] })
1173
+ ] }),
1174
+ /* @__PURE__ */ t("div", { className: "settings-section", children: [
1175
+ /* @__PURE__ */ e("h4", { children: "Audio" }),
1176
+ /* @__PURE__ */ t("label", { className: "checkbox-label", children: [
1177
+ /* @__PURE__ */ e(
1178
+ "input",
1179
+ {
1180
+ type: "checkbox",
1181
+ checked: s.audio.enabled,
1182
+ onChange: (i) => x({
1183
+ audio: { ...s.audio, enabled: i.target.checked }
1184
+ })
1185
+ }
1186
+ ),
1187
+ "Enable Audio"
1188
+ ] }),
1189
+ s.audio.enabled && /* @__PURE__ */ t(le, { children: [
1190
+ /* @__PURE__ */ t("label", { children: [
1191
+ "Source",
1192
+ /* @__PURE__ */ t(
1193
+ "select",
1194
+ {
1195
+ value: s.audio.source,
1196
+ onChange: (i) => x({
1197
+ audio: {
1198
+ ...s.audio,
1199
+ source: i.target.value
1200
+ }
1201
+ }),
1202
+ children: [
1203
+ /* @__PURE__ */ e("option", { value: "system", children: "System Audio" }),
1204
+ /* @__PURE__ */ e("option", { value: "microphone", children: "Microphone" }),
1205
+ /* @__PURE__ */ e("option", { value: "both", children: "Both" })
1206
+ ]
1207
+ }
1208
+ )
1209
+ ] }),
1210
+ /* @__PURE__ */ t("label", { className: "checkbox-label", children: [
1211
+ /* @__PURE__ */ e(
1212
+ "input",
1213
+ {
1214
+ type: "checkbox",
1215
+ checked: s.audio.echoCancellation,
1216
+ onChange: (i) => x({
1217
+ audio: { ...s.audio, echoCancellation: i.target.checked }
1218
+ })
1219
+ }
1220
+ ),
1221
+ "Echo Cancellation"
1222
+ ] }),
1223
+ /* @__PURE__ */ t("label", { className: "checkbox-label", children: [
1224
+ /* @__PURE__ */ e(
1225
+ "input",
1226
+ {
1227
+ type: "checkbox",
1228
+ checked: s.audio.noiseSuppression,
1229
+ onChange: (i) => x({
1230
+ audio: { ...s.audio, noiseSuppression: i.target.checked }
1231
+ })
1232
+ }
1233
+ ),
1234
+ "Noise Suppression"
1235
+ ] })
1236
+ ] })
1237
+ ] }),
1238
+ /* @__PURE__ */ t("div", { className: "settings-section", children: [
1239
+ /* @__PURE__ */ e("h4", { children: "Output" }),
1240
+ /* @__PURE__ */ t("label", { children: [
1241
+ "Format",
1242
+ /* @__PURE__ */ t(
1243
+ "select",
1244
+ {
1245
+ value: s.output.format,
1246
+ onChange: (i) => x({
1247
+ output: { ...s.output, format: i.target.value }
1248
+ }),
1249
+ children: [
1250
+ /* @__PURE__ */ e("option", { value: "webm", children: "WebM (Best Web)" }),
1251
+ /* @__PURE__ */ e("option", { value: "mp4", children: "MP4 (Most Compatible)" }),
1252
+ /* @__PURE__ */ e("option", { value: "mkv", children: "MKV (Lossless)" })
1253
+ ]
1254
+ }
1255
+ )
1256
+ ] }),
1257
+ /* @__PURE__ */ t("label", { children: [
1258
+ "Quality",
1259
+ /* @__PURE__ */ t(
1260
+ "select",
1261
+ {
1262
+ value: s.output.quality,
1263
+ onChange: (i) => x({
1264
+ output: {
1265
+ ...s.output,
1266
+ quality: i.target.value
1267
+ }
1268
+ }),
1269
+ children: [
1270
+ /* @__PURE__ */ e("option", { value: "low", children: "Low (Smaller file)" }),
1271
+ /* @__PURE__ */ e("option", { value: "medium", children: "Medium" }),
1272
+ /* @__PURE__ */ e("option", { value: "high", children: "High (Recommended)" }),
1273
+ /* @__PURE__ */ e("option", { value: "lossless", children: "Lossless (Largest file)" })
1274
+ ]
1275
+ }
1276
+ )
1277
+ ] })
1278
+ ] })
1279
+ ] })
1280
+ ] });
1281
+ }, ke = {
1282
+ id: $(),
1283
+ name: "My Stream",
1284
+ protocol: "rtmp",
1285
+ destinations: [],
1286
+ sources: [],
1287
+ layout: {
1288
+ name: "Default",
1289
+ // Compositor canvas fill: ctx.fillStyle cannot read var(), so this is a literal.
1290
+ canvas: { width: 1920, height: 1080, backgroundColor: "#000000" },
1291
+ layers: []
1292
+ },
1293
+ settings: {
1294
+ video: {
1295
+ resolution: { width: 1920, height: 1080 },
1296
+ frameRate: 30,
1297
+ codec: "h264",
1298
+ bitrate: 6e3,
1299
+ keyframe: 2,
1300
+ profile: "high"
1301
+ },
1302
+ audio: {
1303
+ sampleRate: 48e3,
1304
+ bitrate: 160,
1305
+ channels: 2,
1306
+ codec: "aac"
1307
+ }
1308
+ }
1309
+ }, ce = [
1310
+ {
1311
+ platform: "youtube",
1312
+ name: "YouTube",
1313
+ icon: "video",
1314
+ defaultUrl: "rtmp://a.rtmp.youtube.com/live2"
1315
+ },
1316
+ { platform: "twitch", name: "Twitch", icon: "gamepad", defaultUrl: "rtmp://live.twitch.tv/app" },
1317
+ {
1318
+ platform: "facebook",
1319
+ name: "Facebook",
1320
+ icon: "users",
1321
+ defaultUrl: "rtmps://live-api-s.facebook.com:443/rtmp"
1322
+ },
1323
+ { platform: "custom-rtmp", name: "Custom RTMP", icon: "link", defaultUrl: "" },
1324
+ { platform: "custom-srt", name: "Custom SRT", icon: "lock", defaultUrl: "" }
1325
+ ], re = [
1326
+ { type: "camera", name: "Camera", icon: "camera" },
1327
+ { type: "screen", name: "Screen Capture", icon: "monitor" },
1328
+ { type: "window", name: "Window Capture", icon: "window" },
1329
+ { type: "browser", name: "Browser Source", icon: "globe" },
1330
+ { type: "image", name: "Image", icon: "image" },
1331
+ { type: "video", name: "Video", icon: "video" },
1332
+ { type: "microphone", name: "Microphone", icon: "mic" },
1333
+ { type: "system-audio", name: "System Audio", icon: "volume" }
1334
+ ], _e = ({
1335
+ config: R,
1336
+ onConfigChange: z,
1337
+ onStreamStart: P,
1338
+ onStreamStop: F,
1339
+ onStatsUpdate: V,
1340
+ onError: T,
1341
+ className: d = ""
1342
+ }) => {
1343
+ const [s, A] = b(R || ke), [N, H] = b(
1344
+ "sources"
1345
+ ), [h, k] = b(!1), [y, D] = b({
1346
+ duration: 0,
1347
+ viewers: 0,
1348
+ peakViewers: 0,
1349
+ bitrate: 0,
1350
+ fps: 0,
1351
+ droppedFrames: 0,
1352
+ cpuUsage: 0,
1353
+ memoryUsage: 0
1354
+ }), [w, O] = b(null), [B, C] = b(!1), [j, K] = b(!1), [I, _] = b([s.layout]), [L, ee] = b(0), ae = M(null), S = M(null), g = M(0);
1355
+ oe(() => {
1356
+ R && A(R);
1357
+ }, [R]), oe(() => () => {
1358
+ S.current && clearInterval(S.current);
1359
+ }, []);
1360
+ const f = de(
1361
+ (a) => {
1362
+ const r = { ...s, ...a };
1363
+ A(r), z == null || z(r);
1364
+ },
1365
+ [s, z]
1366
+ ), U = (a) => {
1367
+ const r = ce.find((n) => n.platform === a), o = {
1368
+ id: $(),
1369
+ name: (r == null ? void 0 : r.name) || "Custom",
1370
+ platform: a,
1371
+ url: (r == null ? void 0 : r.defaultUrl) || "",
1372
+ streamKey: "",
1373
+ enabled: !0,
1374
+ status: "idle"
1375
+ };
1376
+ f({ destinations: [...s.destinations, o] }), K(!1);
1377
+ }, G = (a, r) => {
1378
+ f({
1379
+ destinations: s.destinations.map((o) => o.id === a ? { ...o, ...r } : o)
1380
+ });
1381
+ }, W = (a) => {
1382
+ f({ destinations: s.destinations.filter((r) => r.id !== a) });
1383
+ }, Q = async (a) => {
1384
+ const r = re.find((l) => l.type === a), o = {
1385
+ id: $(),
1386
+ type: a,
1387
+ name: `${(r == null ? void 0 : r.name) || a} ${s.sources.filter((l) => l.type === a).length + 1}`,
1388
+ settings: {},
1389
+ volume: 1,
1390
+ muted: !1
1391
+ };
1392
+ try {
1393
+ if (a === "camera" || a === "microphone") {
1394
+ const l = a === "camera" ? { video: !0 } : { audio: !0 }, c = (await navigator.mediaDevices.enumerateDevices()).filter(
1395
+ (m) => a === "camera" ? m.kind === "videoinput" : m.kind === "audioinput"
1396
+ );
1397
+ c.length > 0 && (o.settings.deviceId = c[0].deviceId);
1398
+ } else (a === "screen" || a === "window") && await navigator.mediaDevices.getDisplayMedia({ video: !0 });
1399
+ } catch (l) {
1400
+ console.warn(`Could not access ${a}:`, l);
1401
+ }
1402
+ f({ sources: [...s.sources, o] });
1403
+ const n = {
1404
+ id: $(),
1405
+ sourceId: o.id,
1406
+ position: { x: 0, y: 0 },
1407
+ size: { width: s.layout.canvas.width, height: s.layout.canvas.height },
1408
+ visible: !0,
1409
+ opacity: 1,
1410
+ zIndex: s.layout.layers.length
1411
+ };
1412
+ f({
1413
+ layout: {
1414
+ ...s.layout,
1415
+ layers: [...s.layout.layers, n]
1416
+ }
1417
+ }), C(!1);
1418
+ }, x = (a, r) => {
1419
+ f({
1420
+ sources: s.sources.map((o) => o.id === a ? { ...o, ...r } : o)
1421
+ });
1422
+ }, Y = (a) => {
1423
+ f({
1424
+ sources: s.sources.filter((r) => r.id !== a),
1425
+ layout: {
1426
+ ...s.layout,
1427
+ layers: s.layout.layers.filter((r) => r.sourceId !== a)
1428
+ }
1429
+ });
1430
+ }, E = (a, r) => {
1431
+ f({
1432
+ layout: {
1433
+ ...s.layout,
1434
+ layers: s.layout.layers.map((o) => o.id === a ? { ...o, ...r } : o)
1435
+ }
1436
+ });
1437
+ }, te = (a) => {
1438
+ const r = s.layout.layers.findIndex((o) => o.id === a);
1439
+ if (r < s.layout.layers.length - 1) {
1440
+ const o = [...s.layout.layers];
1441
+ [o[r], o[r + 1]] = [o[r + 1], o[r]], o.forEach((n, l) => {
1442
+ n.zIndex = l;
1443
+ }), f({ layout: { ...s.layout, layers: o } });
1444
+ }
1445
+ }, ie = (a) => {
1446
+ const r = s.layout.layers.findIndex((o) => o.id === a);
1447
+ if (r > 0) {
1448
+ const o = [...s.layout.layers];
1449
+ [o[r], o[r - 1]] = [o[r - 1], o[r]], o.forEach((n, l) => {
1450
+ n.zIndex = l;
1451
+ }), f({ layout: { ...s.layout, layers: o } });
1452
+ }
1453
+ }, Z = () => {
1454
+ const a = {
1455
+ name: `Scene ${I.length + 1}`,
1456
+ canvas: { ...s.layout.canvas },
1457
+ layers: []
1458
+ };
1459
+ _([...I, a]);
1460
+ }, J = (a) => {
1461
+ const r = [...I];
1462
+ r[L] = s.layout, _(r), ee(a), f({ layout: I[a] });
1463
+ }, X = async () => {
1464
+ try {
1465
+ f({
1466
+ destinations: s.destinations.map(
1467
+ (a) => a.enabled ? { ...a, status: "connecting" } : a
1468
+ )
1469
+ }), await new Promise((a) => setTimeout(a, 2e3)), f({
1470
+ destinations: s.destinations.map(
1471
+ (a) => a.enabled ? { ...a, status: "live" } : a
1472
+ )
1473
+ }), k(!0), g.current = Date.now(), P == null || P(), S.current = setInterval(() => {
1474
+ const a = {
1475
+ duration: (Date.now() - g.current) / 1e3,
1476
+ viewers: Math.floor(Math.random() * 100) + y.viewers,
1477
+ peakViewers: Math.max(y.peakViewers, y.viewers),
1478
+ bitrate: s.settings.video.bitrate + Math.floor(Math.random() * 500 - 250),
1479
+ fps: s.settings.video.frameRate - Math.random() * 2,
1480
+ droppedFrames: y.droppedFrames + (Math.random() > 0.95 ? 1 : 0),
1481
+ cpuUsage: 15 + Math.random() * 30,
1482
+ memoryUsage: 40 + Math.random() * 20
1483
+ };
1484
+ D(a), V == null || V(a);
1485
+ }, 1e3);
1486
+ } catch (a) {
1487
+ T == null || T(a instanceof Error ? a : new Error("Failed to start stream")), f({
1488
+ destinations: s.destinations.map((r) => ({
1489
+ ...r,
1490
+ status: "error"
1491
+ }))
1492
+ });
1493
+ }
1494
+ }, q = () => {
1495
+ S.current && clearInterval(S.current), f({
1496
+ destinations: s.destinations.map((a) => ({ ...a, status: "idle" }))
1497
+ }), k(!1), F == null || F();
1498
+ }, ne = (a) => {
1499
+ const r = Math.floor(a / 3600), o = Math.floor(a % 3600 / 60), n = Math.floor(a % 60);
1500
+ return `${r.toString().padStart(2, "0")}:${o.toString().padStart(2, "0")}:${n.toString().padStart(2, "0")}`;
1501
+ }, se = (a) => {
1502
+ switch (a) {
1503
+ case "live":
1504
+ return "var(--nice-success, #00ff00)";
1505
+ case "connecting":
1506
+ return "var(--nice-warning, #ffff00)";
1507
+ case "error":
1508
+ return "var(--nice-danger, #ff0000)";
1509
+ default:
1510
+ return "var(--nice-text-secondary, #888888)";
1511
+ }
1512
+ };
1513
+ return /* @__PURE__ */ t("div", { className: `nice-live-streaming ${d}`, children: [
1514
+ /* @__PURE__ */ t("header", { className: "streaming__header", children: [
1515
+ /* @__PURE__ */ t("div", { className: "header__title", children: [
1516
+ /* @__PURE__ */ e(
1517
+ "input",
1518
+ {
1519
+ type: "text",
1520
+ value: s.name,
1521
+ onChange: (a) => f({ name: a.target.value }),
1522
+ className: "stream-name-input"
1523
+ }
1524
+ ),
1525
+ h && /* @__PURE__ */ t("span", { className: "live-badge", children: [
1526
+ /* @__PURE__ */ e("span", { className: "live-dot" }),
1527
+ " LIVE"
1528
+ ] })
1529
+ ] }),
1530
+ /* @__PURE__ */ e("div", { className: "header__stats", children: h && /* @__PURE__ */ t(le, { children: [
1531
+ /* @__PURE__ */ t("span", { className: "stat-item", children: [
1532
+ /* @__PURE__ */ e(u, { name: "clock", size: 14 }),
1533
+ " ",
1534
+ ne(y.duration)
1535
+ ] }),
1536
+ /* @__PURE__ */ t("span", { className: "stat-item", children: [
1537
+ /* @__PURE__ */ e(u, { name: "users", size: 14 }),
1538
+ " ",
1539
+ y.viewers
1540
+ ] }),
1541
+ /* @__PURE__ */ t("span", { className: "stat-item", children: [
1542
+ /* @__PURE__ */ e(u, { name: "bar-chart", size: 14 }),
1543
+ " ",
1544
+ Math.round(y.bitrate),
1545
+ " kbps"
1546
+ ] }),
1547
+ /* @__PURE__ */ t("span", { className: "stat-item", children: [
1548
+ /* @__PURE__ */ e(u, { name: "video", size: 14 }),
1549
+ " ",
1550
+ y.fps.toFixed(1),
1551
+ " fps"
1552
+ ] })
1553
+ ] }) }),
1554
+ /* @__PURE__ */ e("div", { className: "header__actions", children: h ? /* @__PURE__ */ e("button", { className: "action-button action-button--stop", onClick: q, children: "End Stream" }) : /* @__PURE__ */ e(
1555
+ "button",
1556
+ {
1557
+ className: "action-button action-button--go-live",
1558
+ onClick: X,
1559
+ disabled: s.destinations.filter((a) => a.enabled).length === 0,
1560
+ children: "Go Live"
1561
+ }
1562
+ ) })
1563
+ ] }),
1564
+ /* @__PURE__ */ t("div", { className: "streaming__main", children: [
1565
+ /* @__PURE__ */ t("div", { className: "streaming__preview", children: [
1566
+ /* @__PURE__ */ t("div", { className: "scenes-bar", children: [
1567
+ I.map((a, r) => /* @__PURE__ */ e(
1568
+ "button",
1569
+ {
1570
+ className: `scene-button ${L === r ? "scene-button--active" : ""}`,
1571
+ onClick: () => J(r),
1572
+ children: a.name
1573
+ },
1574
+ r
1575
+ )),
1576
+ /* @__PURE__ */ e("button", { className: "scene-button scene-button--add", onClick: Z, children: "+" })
1577
+ ] }),
1578
+ /* @__PURE__ */ e(
1579
+ "div",
1580
+ {
1581
+ ref: ae,
1582
+ className: "preview-canvas",
1583
+ style: {
1584
+ aspectRatio: `${s.layout.canvas.width}/${s.layout.canvas.height}`,
1585
+ backgroundColor: s.layout.canvas.backgroundColor
1586
+ },
1587
+ children: s.layout.layers.sort((a, r) => a.zIndex - r.zIndex).map((a) => {
1588
+ var o;
1589
+ const r = s.sources.find((n) => n.id === a.sourceId);
1590
+ return !a.visible || !r ? null : /* @__PURE__ */ e(
1591
+ "div",
1592
+ {
1593
+ className: `canvas-layer ${w === a.id ? "canvas-layer--selected" : ""}`,
1594
+ style: {
1595
+ left: `${a.position.x / s.layout.canvas.width * 100}%`,
1596
+ top: `${a.position.y / s.layout.canvas.height * 100}%`,
1597
+ width: `${a.size.width / s.layout.canvas.width * 100}%`,
1598
+ height: `${a.size.height / s.layout.canvas.height * 100}%`,
1599
+ opacity: a.opacity,
1600
+ zIndex: a.zIndex
1601
+ },
1602
+ onClick: () => O(a.id),
1603
+ children: /* @__PURE__ */ t("div", { className: "layer-content", children: [
1604
+ /* @__PURE__ */ e("span", { className: "layer-icon", children: /* @__PURE__ */ e(
1605
+ u,
1606
+ {
1607
+ name: ((o = re.find((n) => n.type === r.type)) == null ? void 0 : o.icon) ?? "box",
1608
+ size: 16
1609
+ }
1610
+ ) }),
1611
+ /* @__PURE__ */ e("span", { className: "layer-name", children: r.name })
1612
+ ] })
1613
+ },
1614
+ a.id
1615
+ );
1616
+ })
1617
+ }
1618
+ )
1619
+ ] }),
1620
+ /* @__PURE__ */ t("aside", { className: "streaming__panel", children: [
1621
+ /* @__PURE__ */ e("div", { className: "panel-tabs", children: ["sources", "audio", "destinations", "settings"].map((a) => /* @__PURE__ */ e(
1622
+ "button",
1623
+ {
1624
+ className: `panel-tab ${N === a ? "panel-tab--active" : ""}`,
1625
+ onClick: () => H(a),
1626
+ children: a.charAt(0).toUpperCase() + a.slice(1)
1627
+ },
1628
+ a
1629
+ )) }),
1630
+ /* @__PURE__ */ t("div", { className: "panel-content", children: [
1631
+ N === "sources" && /* @__PURE__ */ t("div", { className: "sources-panel", children: [
1632
+ /* @__PURE__ */ t("div", { className: "panel-header", children: [
1633
+ /* @__PURE__ */ e("h3", { children: "Sources" }),
1634
+ /* @__PURE__ */ e(
1635
+ "button",
1636
+ {
1637
+ className: "add-button",
1638
+ onClick: () => C(!0),
1639
+ disabled: h,
1640
+ children: "+ Add"
1641
+ }
1642
+ )
1643
+ ] }),
1644
+ /* @__PURE__ */ e("div", { className: "sources-list", children: s.sources.filter((a) => a.type !== "microphone" && a.type !== "system-audio").map((a) => {
1645
+ var o;
1646
+ const r = s.layout.layers.find((n) => n.sourceId === a.id);
1647
+ return /* @__PURE__ */ t(
1648
+ "div",
1649
+ {
1650
+ className: `source-item ${w === (r == null ? void 0 : r.id) ? "source-item--selected" : ""}`,
1651
+ onClick: () => r && O(r.id),
1652
+ children: [
1653
+ /* @__PURE__ */ e("span", { className: "source-icon", children: /* @__PURE__ */ e(
1654
+ u,
1655
+ {
1656
+ name: ((o = re.find((n) => n.type === a.type)) == null ? void 0 : o.icon) ?? "box",
1657
+ size: 16
1658
+ }
1659
+ ) }),
1660
+ /* @__PURE__ */ e("span", { className: "source-name", children: a.name }),
1661
+ /* @__PURE__ */ t("div", { className: "source-controls", children: [
1662
+ /* @__PURE__ */ e(
1663
+ "button",
1664
+ {
1665
+ className: r != null && r.visible ? "" : "inactive",
1666
+ onClick: (n) => {
1667
+ n.stopPropagation(), r && E(r.id, { visible: !r.visible });
1668
+ },
1669
+ children: /* @__PURE__ */ e(u, { name: r != null && r.visible ? "eye" : "eye-off", size: 14 })
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ e(
1673
+ "button",
1674
+ {
1675
+ onClick: (n) => {
1676
+ n.stopPropagation(), r && te(r.id);
1677
+ },
1678
+ children: /* @__PURE__ */ e(u, { name: "arrow-up", size: 14 })
1679
+ }
1680
+ ),
1681
+ /* @__PURE__ */ e(
1682
+ "button",
1683
+ {
1684
+ onClick: (n) => {
1685
+ n.stopPropagation(), r && ie(r.id);
1686
+ },
1687
+ children: /* @__PURE__ */ e(u, { name: "arrow-down", size: 14 })
1688
+ }
1689
+ ),
1690
+ /* @__PURE__ */ e(
1691
+ "button",
1692
+ {
1693
+ onClick: (n) => {
1694
+ n.stopPropagation(), Y(a.id);
1695
+ },
1696
+ disabled: h,
1697
+ children: /* @__PURE__ */ e(u, { name: "trash", size: 14 })
1698
+ }
1699
+ )
1700
+ ] })
1701
+ ]
1702
+ },
1703
+ a.id
1704
+ );
1705
+ }) }),
1706
+ w && /* @__PURE__ */ t("div", { className: "layer-properties", children: [
1707
+ /* @__PURE__ */ e("h4", { children: "Properties" }),
1708
+ (() => {
1709
+ const a = s.layout.layers.find((r) => r.id === w);
1710
+ return a ? /* @__PURE__ */ t(le, { children: [
1711
+ /* @__PURE__ */ t("label", { children: [
1712
+ "X Position",
1713
+ /* @__PURE__ */ e(
1714
+ "input",
1715
+ {
1716
+ type: "number",
1717
+ value: a.position.x,
1718
+ onChange: (r) => E(a.id, {
1719
+ position: { ...a.position, x: parseInt(r.target.value) || 0 }
1720
+ })
1721
+ }
1722
+ )
1723
+ ] }),
1724
+ /* @__PURE__ */ t("label", { children: [
1725
+ "Y Position",
1726
+ /* @__PURE__ */ e(
1727
+ "input",
1728
+ {
1729
+ type: "number",
1730
+ value: a.position.y,
1731
+ onChange: (r) => E(a.id, {
1732
+ position: { ...a.position, y: parseInt(r.target.value) || 0 }
1733
+ })
1734
+ }
1735
+ )
1736
+ ] }),
1737
+ /* @__PURE__ */ t("label", { children: [
1738
+ "Width",
1739
+ /* @__PURE__ */ e(
1740
+ "input",
1741
+ {
1742
+ type: "number",
1743
+ value: a.size.width,
1744
+ onChange: (r) => E(a.id, {
1745
+ size: { ...a.size, width: parseInt(r.target.value) || 100 }
1746
+ })
1747
+ }
1748
+ )
1749
+ ] }),
1750
+ /* @__PURE__ */ t("label", { children: [
1751
+ "Height",
1752
+ /* @__PURE__ */ e(
1753
+ "input",
1754
+ {
1755
+ type: "number",
1756
+ value: a.size.height,
1757
+ onChange: (r) => E(a.id, {
1758
+ size: { ...a.size, height: parseInt(r.target.value) || 100 }
1759
+ })
1760
+ }
1761
+ )
1762
+ ] }),
1763
+ /* @__PURE__ */ t("label", { children: [
1764
+ "Opacity",
1765
+ /* @__PURE__ */ e(
1766
+ "input",
1767
+ {
1768
+ type: "range",
1769
+ min: "0",
1770
+ max: "1",
1771
+ step: "0.1",
1772
+ value: a.opacity,
1773
+ onChange: (r) => E(a.id, {
1774
+ opacity: parseFloat(r.target.value)
1775
+ })
1776
+ }
1777
+ )
1778
+ ] })
1779
+ ] }) : null;
1780
+ })()
1781
+ ] })
1782
+ ] }),
1783
+ N === "audio" && /* @__PURE__ */ t("div", { className: "audio-panel", children: [
1784
+ /* @__PURE__ */ t("div", { className: "panel-header", children: [
1785
+ /* @__PURE__ */ e("h3", { children: "Audio Mixer" }),
1786
+ /* @__PURE__ */ e(
1787
+ "button",
1788
+ {
1789
+ className: "add-button",
1790
+ onClick: () => {
1791
+ C(!0);
1792
+ },
1793
+ disabled: h,
1794
+ children: "+ Add"
1795
+ }
1796
+ )
1797
+ ] }),
1798
+ /* @__PURE__ */ t("div", { className: "audio-sources", children: [
1799
+ s.sources.filter(
1800
+ (a) => a.type === "microphone" || a.type === "system-audio" || a.type === "video"
1801
+ ).map((a) => {
1802
+ var r;
1803
+ return /* @__PURE__ */ t("div", { className: "audio-source", children: [
1804
+ /* @__PURE__ */ t("div", { className: "audio-header", children: [
1805
+ /* @__PURE__ */ e("span", { className: "audio-icon", children: /* @__PURE__ */ e(
1806
+ u,
1807
+ {
1808
+ name: ((r = re.find((o) => o.type === a.type)) == null ? void 0 : r.icon) ?? "box",
1809
+ size: 16
1810
+ }
1811
+ ) }),
1812
+ /* @__PURE__ */ e("span", { className: "audio-name", children: a.name }),
1813
+ /* @__PURE__ */ e(
1814
+ "button",
1815
+ {
1816
+ className: a.muted ? "muted" : "",
1817
+ onClick: () => x(a.id, { muted: !a.muted }),
1818
+ children: /* @__PURE__ */ e(u, { name: a.muted ? "volume-off" : "volume", size: 14 })
1819
+ }
1820
+ )
1821
+ ] }),
1822
+ /* @__PURE__ */ t("div", { className: "audio-slider", children: [
1823
+ /* @__PURE__ */ e(
1824
+ "input",
1825
+ {
1826
+ type: "range",
1827
+ min: "0",
1828
+ max: "1",
1829
+ step: "0.01",
1830
+ value: a.volume ?? 1,
1831
+ onChange: (o) => x(a.id, { volume: parseFloat(o.target.value) }),
1832
+ disabled: a.muted
1833
+ }
1834
+ ),
1835
+ /* @__PURE__ */ t("span", { className: "volume-value", children: [
1836
+ Math.round((a.volume ?? 1) * 100),
1837
+ "%"
1838
+ ] })
1839
+ ] }),
1840
+ /* @__PURE__ */ e("div", { className: "audio-meter", children: /* @__PURE__ */ e(
1841
+ "div",
1842
+ {
1843
+ className: "meter-fill",
1844
+ style: { width: `${(a.volume ?? 1) * 70 + Math.random() * 30}%` }
1845
+ }
1846
+ ) })
1847
+ ] }, a.id);
1848
+ }),
1849
+ s.sources.filter(
1850
+ (a) => a.type === "microphone" || a.type === "system-audio"
1851
+ ).length === 0 && /* @__PURE__ */ e("p", { className: "empty-message", children: "No audio sources added" })
1852
+ ] })
1853
+ ] }),
1854
+ N === "destinations" && /* @__PURE__ */ t("div", { className: "destinations-panel", children: [
1855
+ /* @__PURE__ */ t("div", { className: "panel-header", children: [
1856
+ /* @__PURE__ */ e("h3", { children: "Destinations" }),
1857
+ /* @__PURE__ */ e(
1858
+ "button",
1859
+ {
1860
+ className: "add-button",
1861
+ onClick: () => K(!0),
1862
+ disabled: h,
1863
+ children: "+ Add"
1864
+ }
1865
+ )
1866
+ ] }),
1867
+ /* @__PURE__ */ t("div", { className: "destinations-list", children: [
1868
+ s.destinations.map((a) => {
1869
+ var r;
1870
+ return /* @__PURE__ */ t("div", { className: "destination-item", children: [
1871
+ /* @__PURE__ */ t("div", { className: "destination-header", children: [
1872
+ /* @__PURE__ */ e(
1873
+ "span",
1874
+ {
1875
+ className: "status-indicator",
1876
+ style: { backgroundColor: se(a.status) }
1877
+ }
1878
+ ),
1879
+ /* @__PURE__ */ e("span", { className: "destination-icon", children: /* @__PURE__ */ e(
1880
+ u,
1881
+ {
1882
+ name: ((r = ce.find((o) => o.platform === a.platform)) == null ? void 0 : r.icon) ?? "link",
1883
+ size: 16
1884
+ }
1885
+ ) }),
1886
+ /* @__PURE__ */ e("span", { className: "destination-name", children: a.name }),
1887
+ /* @__PURE__ */ t("label", { className: "toggle", children: [
1888
+ /* @__PURE__ */ e(
1889
+ "input",
1890
+ {
1891
+ type: "checkbox",
1892
+ checked: a.enabled,
1893
+ onChange: (o) => G(a.id, { enabled: o.target.checked }),
1894
+ disabled: h
1895
+ }
1896
+ ),
1897
+ /* @__PURE__ */ e("span", { className: "toggle-slider" })
1898
+ ] })
1899
+ ] }),
1900
+ /* @__PURE__ */ t("div", { className: "destination-config", children: [
1901
+ /* @__PURE__ */ t("label", { children: [
1902
+ "Server URL",
1903
+ /* @__PURE__ */ e(
1904
+ "input",
1905
+ {
1906
+ type: "text",
1907
+ value: a.url,
1908
+ onChange: (o) => G(a.id, { url: o.target.value }),
1909
+ placeholder: "rtmp://...",
1910
+ disabled: h
1911
+ }
1912
+ )
1913
+ ] }),
1914
+ /* @__PURE__ */ t("label", { children: [
1915
+ "Stream Key",
1916
+ /* @__PURE__ */ e(
1917
+ "input",
1918
+ {
1919
+ type: "password",
1920
+ value: a.streamKey || "",
1921
+ onChange: (o) => G(a.id, { streamKey: o.target.value }),
1922
+ placeholder: "Enter stream key",
1923
+ disabled: h
1924
+ }
1925
+ )
1926
+ ] })
1927
+ ] }),
1928
+ /* @__PURE__ */ e(
1929
+ "button",
1930
+ {
1931
+ className: "remove-button",
1932
+ onClick: () => W(a.id),
1933
+ disabled: h,
1934
+ children: "Remove"
1935
+ }
1936
+ )
1937
+ ] }, a.id);
1938
+ }),
1939
+ s.destinations.length === 0 && /* @__PURE__ */ e("p", { className: "empty-message", children: "No destinations configured" })
1940
+ ] })
1941
+ ] }),
1942
+ N === "settings" && /* @__PURE__ */ t("div", { className: "settings-panel", children: [
1943
+ /* @__PURE__ */ t("div", { className: "setting-section", children: [
1944
+ /* @__PURE__ */ e("h4", { children: "Video" }),
1945
+ /* @__PURE__ */ t("label", { children: [
1946
+ "Resolution",
1947
+ /* @__PURE__ */ t(
1948
+ "select",
1949
+ {
1950
+ value: `${s.settings.video.resolution.width}x${s.settings.video.resolution.height}`,
1951
+ onChange: (a) => {
1952
+ const [r, o] = a.target.value.split("x").map(Number);
1953
+ f({
1954
+ settings: {
1955
+ ...s.settings,
1956
+ video: { ...s.settings.video, resolution: { width: r, height: o } }
1957
+ },
1958
+ layout: {
1959
+ ...s.layout,
1960
+ canvas: { ...s.layout.canvas, width: r, height: o }
1961
+ }
1962
+ });
1963
+ },
1964
+ disabled: h,
1965
+ children: [
1966
+ /* @__PURE__ */ e("option", { value: "1920x1080", children: "1080p (1920x1080)" }),
1967
+ /* @__PURE__ */ e("option", { value: "1280x720", children: "720p (1280x720)" }),
1968
+ /* @__PURE__ */ e("option", { value: "2560x1440", children: "1440p (2560x1440)" })
1969
+ ]
1970
+ }
1971
+ )
1972
+ ] }),
1973
+ /* @__PURE__ */ t("label", { children: [
1974
+ "Frame Rate",
1975
+ /* @__PURE__ */ t(
1976
+ "select",
1977
+ {
1978
+ value: s.settings.video.frameRate,
1979
+ onChange: (a) => f({
1980
+ settings: {
1981
+ ...s.settings,
1982
+ video: {
1983
+ ...s.settings.video,
1984
+ frameRate: parseInt(a.target.value)
1985
+ }
1986
+ }
1987
+ }),
1988
+ disabled: h,
1989
+ children: [
1990
+ /* @__PURE__ */ e("option", { value: "24", children: "24 fps" }),
1991
+ /* @__PURE__ */ e("option", { value: "30", children: "30 fps" }),
1992
+ /* @__PURE__ */ e("option", { value: "60", children: "60 fps" })
1993
+ ]
1994
+ }
1995
+ )
1996
+ ] }),
1997
+ /* @__PURE__ */ t("label", { children: [
1998
+ "Bitrate (kbps)",
1999
+ /* @__PURE__ */ e(
2000
+ "input",
2001
+ {
2002
+ type: "number",
2003
+ value: s.settings.video.bitrate,
2004
+ onChange: (a) => f({
2005
+ settings: {
2006
+ ...s.settings,
2007
+ video: {
2008
+ ...s.settings.video,
2009
+ bitrate: parseInt(a.target.value) || 6e3
2010
+ }
2011
+ }
2012
+ }),
2013
+ min: "1000",
2014
+ max: "50000",
2015
+ disabled: h
2016
+ }
2017
+ )
2018
+ ] }),
2019
+ /* @__PURE__ */ t("label", { children: [
2020
+ "Keyframe Interval (sec)",
2021
+ /* @__PURE__ */ e(
2022
+ "input",
2023
+ {
2024
+ type: "number",
2025
+ value: s.settings.video.keyframe,
2026
+ onChange: (a) => f({
2027
+ settings: {
2028
+ ...s.settings,
2029
+ video: {
2030
+ ...s.settings.video,
2031
+ keyframe: parseInt(a.target.value) || 2
2032
+ }
2033
+ }
2034
+ }),
2035
+ min: "1",
2036
+ max: "10",
2037
+ disabled: h
2038
+ }
2039
+ )
2040
+ ] })
2041
+ ] }),
2042
+ /* @__PURE__ */ t("div", { className: "setting-section", children: [
2043
+ /* @__PURE__ */ e("h4", { children: "Audio" }),
2044
+ /* @__PURE__ */ t("label", { children: [
2045
+ "Sample Rate",
2046
+ /* @__PURE__ */ t(
2047
+ "select",
2048
+ {
2049
+ value: s.settings.audio.sampleRate,
2050
+ onChange: (a) => f({
2051
+ settings: {
2052
+ ...s.settings,
2053
+ audio: {
2054
+ ...s.settings.audio,
2055
+ sampleRate: parseInt(a.target.value)
2056
+ }
2057
+ }
2058
+ }),
2059
+ disabled: h,
2060
+ children: [
2061
+ /* @__PURE__ */ e("option", { value: "44100", children: "44.1 kHz" }),
2062
+ /* @__PURE__ */ e("option", { value: "48000", children: "48 kHz" })
2063
+ ]
2064
+ }
2065
+ )
2066
+ ] }),
2067
+ /* @__PURE__ */ t("label", { children: [
2068
+ "Audio Bitrate (kbps)",
2069
+ /* @__PURE__ */ t(
2070
+ "select",
2071
+ {
2072
+ value: s.settings.audio.bitrate,
2073
+ onChange: (a) => f({
2074
+ settings: {
2075
+ ...s.settings,
2076
+ audio: { ...s.settings.audio, bitrate: parseInt(a.target.value) }
2077
+ }
2078
+ }),
2079
+ disabled: h,
2080
+ children: [
2081
+ /* @__PURE__ */ e("option", { value: "96", children: "96 kbps" }),
2082
+ /* @__PURE__ */ e("option", { value: "128", children: "128 kbps" }),
2083
+ /* @__PURE__ */ e("option", { value: "160", children: "160 kbps" }),
2084
+ /* @__PURE__ */ e("option", { value: "320", children: "320 kbps" })
2085
+ ]
2086
+ }
2087
+ )
2088
+ ] })
2089
+ ] })
2090
+ ] })
2091
+ ] })
2092
+ ] })
2093
+ ] }),
2094
+ h && /* @__PURE__ */ e("footer", { className: "streaming__footer", children: /* @__PURE__ */ t("div", { className: "footer-stats", children: [
2095
+ /* @__PURE__ */ t("span", { className: "stat", children: [
2096
+ /* @__PURE__ */ e("label", { children: "CPU" }),
2097
+ /* @__PURE__ */ t("span", { className: "value", children: [
2098
+ y.cpuUsage.toFixed(1),
2099
+ "%"
2100
+ ] })
2101
+ ] }),
2102
+ /* @__PURE__ */ t("span", { className: "stat", children: [
2103
+ /* @__PURE__ */ e("label", { children: "Memory" }),
2104
+ /* @__PURE__ */ t("span", { className: "value", children: [
2105
+ y.memoryUsage.toFixed(1),
2106
+ "%"
2107
+ ] })
2108
+ ] }),
2109
+ /* @__PURE__ */ t("span", { className: "stat", children: [
2110
+ /* @__PURE__ */ e("label", { children: "Dropped" }),
2111
+ /* @__PURE__ */ e("span", { className: "value", children: y.droppedFrames })
2112
+ ] }),
2113
+ /* @__PURE__ */ t("span", { className: "stat", children: [
2114
+ /* @__PURE__ */ e("label", { children: "Peak Viewers" }),
2115
+ /* @__PURE__ */ e("span", { className: "value", children: y.peakViewers })
2116
+ ] })
2117
+ ] }) }),
2118
+ B && /* @__PURE__ */ e("div", { className: "modal-overlay", children: /* @__PURE__ */ t("div", { className: "modal", children: [
2119
+ /* @__PURE__ */ t("div", { className: "modal-header", children: [
2120
+ /* @__PURE__ */ e("h3", { children: "Add Source" }),
2121
+ /* @__PURE__ */ e(
2122
+ "button",
2123
+ {
2124
+ "aria-label": "Close",
2125
+ className: "close-button",
2126
+ onClick: () => C(!1),
2127
+ children: /* @__PURE__ */ e(u, { name: "close", size: 16 })
2128
+ }
2129
+ )
2130
+ ] }),
2131
+ /* @__PURE__ */ e("div", { className: "modal-content", children: /* @__PURE__ */ e("div", { className: "source-type-grid", children: re.map((a) => /* @__PURE__ */ t(
2132
+ "button",
2133
+ {
2134
+ className: "source-type-button",
2135
+ onClick: () => Q(a.type),
2136
+ children: [
2137
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: a.icon, size: 24 }) }),
2138
+ /* @__PURE__ */ e("span", { className: "name", children: a.name })
2139
+ ]
2140
+ },
2141
+ a.type
2142
+ )) }) })
2143
+ ] }) }),
2144
+ j && /* @__PURE__ */ e("div", { className: "modal-overlay", children: /* @__PURE__ */ t("div", { className: "modal", children: [
2145
+ /* @__PURE__ */ t("div", { className: "modal-header", children: [
2146
+ /* @__PURE__ */ e("h3", { children: "Add Destination" }),
2147
+ /* @__PURE__ */ e(
2148
+ "button",
2149
+ {
2150
+ "aria-label": "Close",
2151
+ className: "close-button",
2152
+ onClick: () => K(!1),
2153
+ children: /* @__PURE__ */ e(u, { name: "close", size: 16 })
2154
+ }
2155
+ )
2156
+ ] }),
2157
+ /* @__PURE__ */ e("div", { className: "modal-content", children: /* @__PURE__ */ e("div", { className: "platform-grid", children: ce.map((a) => /* @__PURE__ */ t(
2158
+ "button",
2159
+ {
2160
+ className: "platform-button",
2161
+ onClick: () => U(a.platform),
2162
+ children: [
2163
+ /* @__PURE__ */ e("span", { className: "icon", children: /* @__PURE__ */ e(u, { name: a.icon, size: 24 }) }),
2164
+ /* @__PURE__ */ e("span", { className: "name", children: a.name })
2165
+ ]
2166
+ },
2167
+ a.platform
2168
+ )) }) })
2169
+ ] }) })
2170
+ ] });
2171
+ };
2
2172
  export {
3
- r as NiceLiveStreaming,
4
- a as NiceScreenRecorder,
5
- c as NiceVideoEditor
2173
+ _e as NiceLiveStreaming,
2174
+ Ie as NiceScreenRecorder,
2175
+ ze as NiceVideoEditor
6
2176
  };