@pixerate/editor-svelte 0.62.0 → 0.64.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/video-editor/ClipInspector.svelte +87 -2
- package/dist/video-editor/ClipInspector.svelte.d.ts.map +1 -1
- package/dist/video-editor/TranscriptPanel.svelte +136 -0
- package/dist/video-editor/TranscriptPanel.svelte.d.ts +13 -0
- package/dist/video-editor/TranscriptPanel.svelte.d.ts.map +1 -0
- package/dist/video-editor/VideoEditor.svelte +6 -1
- package/dist/video-editor/VideoEditor.svelte.d.ts +2 -0
- package/dist/video-editor/VideoEditor.svelte.d.ts.map +1 -1
- package/dist/video-editor/index.d.ts +3 -0
- package/dist/video-editor/index.d.ts.map +1 -1
- package/dist/video-editor/index.js +1 -0
- package/package.json +2 -2
|
@@ -2,16 +2,32 @@
|
|
|
2
2
|
import {
|
|
3
3
|
findVideoClip,
|
|
4
4
|
formatVideoTimecode,
|
|
5
|
+
VIDEO_CLIP_ANIMATION_EFFECTS,
|
|
6
|
+
VIDEO_CLIP_ANIMATION_LABELS,
|
|
7
|
+
normalizeVideoGrade,
|
|
8
|
+
VIDEO_GRADE_CONTROLS,
|
|
9
|
+
VIDEO_GRADE_PRESET_NAMES,
|
|
10
|
+
videoGradePreset,
|
|
11
|
+
VIDEO_BLEND_MODE_LABELS,
|
|
12
|
+
VIDEO_BLEND_MODES,
|
|
5
13
|
VIDEO_FADE_CURVE_LABELS,
|
|
6
14
|
VIDEO_FADE_CURVES,
|
|
15
|
+
VIDEO_TRANSITION_LABELS,
|
|
7
16
|
VIDEO_TRANSITION_TYPES,
|
|
17
|
+
VIDEO_WIPE_DIRECTIONS,
|
|
18
|
+
videoTransitionHasDirection,
|
|
8
19
|
videoKeyframeRows,
|
|
20
|
+
videoTransitionAudioCurve,
|
|
9
21
|
videoKeyframeToggleEdit,
|
|
10
22
|
videoKeyframeValueEdit,
|
|
11
23
|
type VideoEdit,
|
|
12
24
|
type VideoEditorController,
|
|
25
|
+
type VideoFadeCurve,
|
|
26
|
+
type VideoGradeControl,
|
|
27
|
+
type VideoGradePreset,
|
|
13
28
|
type VideoKeyframeRow,
|
|
14
|
-
type VideoTransitionType
|
|
29
|
+
type VideoTransitionType,
|
|
30
|
+
type VideoWipeDirection
|
|
15
31
|
} from '@pixerate/editor/video-editor';
|
|
16
32
|
import { videoEditorStateOf } from './createVideoEditor.svelte.js';
|
|
17
33
|
|
|
@@ -88,6 +104,27 @@
|
|
|
88
104
|
if (!type) apply({ op: 'set_transition', clip: clip.id, transition: null }, 'Remove transition');
|
|
89
105
|
else apply({ op: 'set_transition', clip: clip.id, transition: { ...clip.transition, type: type as VideoTransitionType, duration: clip.transition?.duration ?? 500 } }, 'Set transition');
|
|
90
106
|
}
|
|
107
|
+
function gradeValue(c: VideoGradeControl, raw: string) {
|
|
108
|
+
if (!clip) return;
|
|
109
|
+
const n = raw.trim() ? Number(raw) : 0;
|
|
110
|
+
if (!Number.isFinite(n)) {
|
|
111
|
+
localError = { text: `${c.label} must be a number from ${c.min} to ${c.max}.`, revision: editor.revision };
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Out-of-range values are clamped to the control's range.
|
|
115
|
+
set('grade', normalizeVideoGrade({ ...clip.grade, [c.key]: n }), `Change ${c.label.toLowerCase()}`);
|
|
116
|
+
}
|
|
117
|
+
function gradePreset(name: string) {
|
|
118
|
+
const grade = clip && name ? videoGradePreset(name as VideoGradePreset) : undefined;
|
|
119
|
+
if (clip && grade) apply({ op: 'update_clip', clip: clip.id, set: { grade } }, `Apply ${name} look`);
|
|
120
|
+
}
|
|
121
|
+
function transitionAudioCurve(curve: string) {
|
|
122
|
+
if (!clip?.transition) return;
|
|
123
|
+
const { audioCurve: _, ...rest } = clip.transition;
|
|
124
|
+
// The type's own default is stored as no curve, so it follows the type if that changes.
|
|
125
|
+
const next = curve === videoTransitionAudioCurve(rest) ? rest : { ...rest, audioCurve: curve as VideoFadeCurve };
|
|
126
|
+
apply({ op: 'set_transition', clip: clip.id, transition: next }, 'Change transition sound');
|
|
127
|
+
}
|
|
91
128
|
function transitionDuration(raw: string) {
|
|
92
129
|
if (!clip?.transition) return;
|
|
93
130
|
const n = Number(raw);
|
|
@@ -125,6 +162,38 @@
|
|
|
125
162
|
<span class="tabular-nums" data-field="start">{formatVideoTimecode(clip.start, fps)}</span>
|
|
126
163
|
<span class="text-muted-foreground">Duration</span>
|
|
127
164
|
<span class="tabular-nums" data-field="duration">{formatVideoTimecode(clip.duration, fps)} ({(clip.duration / 1000).toFixed(2)} s)</span>
|
|
165
|
+
{#if at?.track.kind === 'video'}
|
|
166
|
+
<span class="text-muted-foreground">Blend</span>
|
|
167
|
+
<select class={input} aria-label="Blend mode" {disabled} value={clip.blend ?? 'normal'} onchange={(e) => set('blend', e.currentTarget.value === 'normal' ? undefined : e.currentTarget.value, 'Change blend mode')} data-field="blend">
|
|
168
|
+
{#each VIDEO_BLEND_MODES as m (m)}
|
|
169
|
+
<option value={m}>{VIDEO_BLEND_MODE_LABELS[m]}</option>
|
|
170
|
+
{/each}
|
|
171
|
+
</select>
|
|
172
|
+
{/if}
|
|
173
|
+
{#if at?.track.kind === 'video'}
|
|
174
|
+
<span class="text-muted-foreground">Look</span>
|
|
175
|
+
<select class={input} aria-label="Apply a look" {disabled} value="" onchange={(e) => gradePreset(e.currentTarget.value)} data-field="gradePreset">
|
|
176
|
+
<option value="">{clip.grade ? 'graded' : 'none'}</option>
|
|
177
|
+
{#each VIDEO_GRADE_PRESET_NAMES as name (name)}
|
|
178
|
+
<option value={name}>{name.replace(/-/g, ' ')}</option>
|
|
179
|
+
{/each}
|
|
180
|
+
</select>
|
|
181
|
+
{#each VIDEO_GRADE_CONTROLS as c (c.key)}
|
|
182
|
+
<span class="text-muted-foreground">{c.label}</span>
|
|
183
|
+
<input class={input} type="number" min={c.min} max={c.max} step={c.step} placeholder="0" aria-label={c.label} {disabled} value={clip.grade?.[c.key] ?? ''} onchange={(e) => gradeValue(c, e.currentTarget.value)} data-field="grade.{c.key}" />
|
|
184
|
+
{/each}
|
|
185
|
+
{/if}
|
|
186
|
+
{#if at?.track.kind === 'video'}
|
|
187
|
+
{#each [{ key: 'animateIn', label: 'Animate in', change: 'Change entrance' }, { key: 'animateOut', label: 'Animate out', change: 'Change exit' }] as const as row (row.key)}
|
|
188
|
+
<span class="text-muted-foreground">{row.label}</span>
|
|
189
|
+
<select class={input} aria-label={row.label} {disabled} value={clip[row.key]?.effect ?? ''} onchange={(e) => set(row.key, e.currentTarget.value ? { ...clip?.[row.key], effect: e.currentTarget.value } : undefined, row.change)} data-field={row.key}>
|
|
190
|
+
<option value="">none</option>
|
|
191
|
+
{#each VIDEO_CLIP_ANIMATION_EFFECTS as effect (effect)}
|
|
192
|
+
<option value={effect}>{VIDEO_CLIP_ANIMATION_LABELS[effect]}</option>
|
|
193
|
+
{/each}
|
|
194
|
+
</select>
|
|
195
|
+
{/each}
|
|
196
|
+
{/if}
|
|
128
197
|
<span class="text-muted-foreground">Fade in</span>
|
|
129
198
|
<input class={input} type="number" min="0" step="100" placeholder="0 ms" aria-label="Fade in" {disabled} value={clip.fadeIn ?? ''} onchange={(e) => number('fadeIn', e.currentTarget.value, 'Change fade in', { min: 0, what: 'Fade in must be a number of ms, 0 or more.' })} data-field="fadeIn" />
|
|
130
199
|
<span class="text-muted-foreground">Fade out</span>
|
|
@@ -179,7 +248,7 @@
|
|
|
179
248
|
<select class={input} aria-label="Transition" {disabled} value={clip.transition?.type ?? ''} onchange={(e) => setTransition(e.currentTarget.value)} data-field="transition">
|
|
180
249
|
<option value="">none</option>
|
|
181
250
|
{#each VIDEO_TRANSITION_TYPES as t (t)}
|
|
182
|
-
<option value={t}>{t}</option>
|
|
251
|
+
<option value={t}>{VIDEO_TRANSITION_LABELS[t]}</option>
|
|
183
252
|
{/each}
|
|
184
253
|
</select>
|
|
185
254
|
{#if clip.transition}
|
|
@@ -187,6 +256,22 @@
|
|
|
187
256
|
<span class="text-[10px] text-muted-foreground">ms</span>
|
|
188
257
|
{/if}
|
|
189
258
|
</div>
|
|
259
|
+
{#if clip.transition && videoTransitionHasDirection(clip.transition.type)}
|
|
260
|
+
<span class="text-muted-foreground">Direction</span>
|
|
261
|
+
<select class={input} aria-label="Transition direction" {disabled} value={clip.transition.direction ?? 'right'} onchange={(e) => clip?.transition && apply({ op: 'set_transition', clip: clip.id, transition: { ...clip.transition, direction: e.currentTarget.value as VideoWipeDirection } }, 'Change transition direction')} data-field="transitionDirection">
|
|
262
|
+
{#each VIDEO_WIPE_DIRECTIONS as d (d)}
|
|
263
|
+
<option value={d}>{d}</option>
|
|
264
|
+
{/each}
|
|
265
|
+
</select>
|
|
266
|
+
{/if}
|
|
267
|
+
{#if clip.transition}
|
|
268
|
+
<span class="text-muted-foreground">Transition sound</span>
|
|
269
|
+
<select class={input} aria-label="Transition sound curve" {disabled} value={videoTransitionAudioCurve(clip.transition)} onchange={(e) => transitionAudioCurve(e.currentTarget.value)} data-field="transitionAudioCurve">
|
|
270
|
+
{#each VIDEO_FADE_CURVES as c (c)}
|
|
271
|
+
<option value={c}>{VIDEO_FADE_CURVE_LABELS[c]}</option>
|
|
272
|
+
{/each}
|
|
273
|
+
</select>
|
|
274
|
+
{/if}
|
|
190
275
|
</div>
|
|
191
276
|
{/if}
|
|
192
277
|
{#if message}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClipInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/ClipInspector.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"ClipInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/ClipInspector.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAsBH,KAAK,qBAAqB,EAO3B,MAAM,+BAA+B,CAAC;AAIvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4OH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
findVideoFillers,
|
|
4
|
+
findVideoTranscriptPauses,
|
|
5
|
+
videoRemoveRangesEdits,
|
|
6
|
+
videoTimelineTranscript,
|
|
7
|
+
videoTranscriptEdit,
|
|
8
|
+
videoWordAt,
|
|
9
|
+
videoWordsRange,
|
|
10
|
+
type VideoEditorController,
|
|
11
|
+
type VideoTimelineWord
|
|
12
|
+
} from '@pixerate/editor/video-editor';
|
|
13
|
+
import { videoEditorStateOf } from './createVideoEditor.svelte.js';
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
controller: VideoEditorController;
|
|
17
|
+
/** Track whose words to show (default: the first audio track with a transcribed clip, else the first video track with one). */
|
|
18
|
+
track?: string;
|
|
19
|
+
/** Allow cutting by text and loading transcripts (default true). */
|
|
20
|
+
editable?: boolean;
|
|
21
|
+
class?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { controller, track, editable = true, class: className = '' }: Props = $props();
|
|
25
|
+
const view = videoEditorStateOf(() => controller);
|
|
26
|
+
const editor = $derived(view.current);
|
|
27
|
+
const canEdit = $derived(editable && !editor.readOnly);
|
|
28
|
+
const words: VideoTimelineWord[] = $derived.by(() => {
|
|
29
|
+
try {
|
|
30
|
+
return videoTimelineTranscript(editor.project, { track });
|
|
31
|
+
} catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const current = $derived(videoWordAt(words, editor.time));
|
|
36
|
+
let anchor = $state<number | null>(null);
|
|
37
|
+
let focus = $state<number | null>(null);
|
|
38
|
+
let message = $state<string | null>(null);
|
|
39
|
+
const selected = $derived(anchor !== null && focus !== null && anchor < words.length && focus < words.length ? ([Math.min(anchor, focus), Math.max(anchor, focus)] as const) : null);
|
|
40
|
+
const sound = $derived(editor.project.assets.filter((a) => a.kind !== 'image'));
|
|
41
|
+
const btn = 'rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40';
|
|
42
|
+
|
|
43
|
+
function cut(ranges: { from: number; to: number }[], label: string, none: string) {
|
|
44
|
+
if (!ranges.length) {
|
|
45
|
+
message = none;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const r = controller.apply(videoRemoveRangesEdits(ranges), label);
|
|
49
|
+
message = r.ok ? null : r.error;
|
|
50
|
+
anchor = null;
|
|
51
|
+
focus = null;
|
|
52
|
+
}
|
|
53
|
+
function cutSelection() {
|
|
54
|
+
if (selected) cut([videoWordsRange(words, selected[0], selected[1])], 'Cut words', 'Select words to cut.');
|
|
55
|
+
}
|
|
56
|
+
function pick(e: MouseEvent, i: number) {
|
|
57
|
+
if (e.shiftKey && anchor !== null) focus = i;
|
|
58
|
+
else {
|
|
59
|
+
anchor = i;
|
|
60
|
+
focus = i;
|
|
61
|
+
controller.seek(words[i].start);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function load(assetId: string, file: File | undefined) {
|
|
65
|
+
if (!file) return;
|
|
66
|
+
try {
|
|
67
|
+
const r = controller.apply(videoTranscriptEdit(assetId, await file.text()), 'Attach transcript');
|
|
68
|
+
message = r.ok ? null : r.error;
|
|
69
|
+
} catch (e) {
|
|
70
|
+
message = e instanceof Error ? e.message : String(e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<!--
|
|
76
|
+
Edit by text: the words the timeline plays, from its media's transcripts. Click a word to go to it,
|
|
77
|
+
Shift-click to select a run of words, then delete them to cut that stretch out. "Remove fillers"
|
|
78
|
+
and "Tighten pauses" cut every um and long gap at once. Each cut is one undo step.
|
|
79
|
+
-->
|
|
80
|
+
<div class="flex flex-col gap-2 text-xs {className}" data-transcript-panel="">
|
|
81
|
+
{#if words.length}
|
|
82
|
+
<div
|
|
83
|
+
class="max-h-48 overflow-y-auto leading-6"
|
|
84
|
+
role="listbox"
|
|
85
|
+
aria-label="Transcript"
|
|
86
|
+
aria-multiselectable="true"
|
|
87
|
+
tabindex="0"
|
|
88
|
+
onkeydown={(e) => {
|
|
89
|
+
if (canEdit && selected && (e.key === 'Delete' || e.key === 'Backspace')) {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
cutSelection();
|
|
92
|
+
}
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
{#each words as w, i (`${w.clip}:${w.index}`)}
|
|
96
|
+
{@const inSelection = selected !== null && i >= selected[0] && i <= selected[1]}
|
|
97
|
+
<span
|
|
98
|
+
role="option"
|
|
99
|
+
aria-selected={inSelection}
|
|
100
|
+
tabindex="-1"
|
|
101
|
+
class="cursor-pointer rounded px-0.5 {inSelection ? 'bg-rose-500/30' : i === current ? 'bg-amber-400/40' : 'hover:bg-muted'}"
|
|
102
|
+
data-word={i}
|
|
103
|
+
data-current={i === current ? '' : undefined}
|
|
104
|
+
data-selected={inSelection ? '' : undefined}
|
|
105
|
+
onclick={(e) => pick(e, i)}
|
|
106
|
+
onkeydown={() => {}}>{w.word}</span
|
|
107
|
+
>{' '}
|
|
108
|
+
{/each}
|
|
109
|
+
</div>
|
|
110
|
+
{#if canEdit}
|
|
111
|
+
<div class="flex flex-wrap gap-1">
|
|
112
|
+
<button type="button" class={btn} disabled={!selected} onclick={cutSelection}>Delete selected words</button>
|
|
113
|
+
<button type="button" class={btn} onclick={() => cut(findVideoFillers(words), 'Remove fillers', 'No filler words found.')}>Remove fillers</button>
|
|
114
|
+
<button type="button" class={btn} onclick={() => cut(findVideoTranscriptPauses(words, { fps: editor.project.fps }), 'Tighten pauses', 'No long pauses found.')}>Tighten pauses</button>
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
117
|
+
{:else}
|
|
118
|
+
<p class="text-muted-foreground" data-transcript-empty="">No transcribed media on the timeline. Load a transcript (Whisper JSON, .srt or .vtt) for a video or audio asset to edit by text.</p>
|
|
119
|
+
{/if}
|
|
120
|
+
{#if canEdit && sound.length}
|
|
121
|
+
<details>
|
|
122
|
+
<summary class="cursor-pointer text-muted-foreground">Transcripts</summary>
|
|
123
|
+
<ul class="mt-1 space-y-1">
|
|
124
|
+
{#each sound as a (a.id)}
|
|
125
|
+
<li class="flex items-center gap-2">
|
|
126
|
+
<span class="min-w-0 flex-1 truncate">{a.name ?? a.id} {a.transcript ? `· ${a.transcript.length} words` : ''}</span>
|
|
127
|
+
<input type="file" accept=".json,.srt,.vtt,application/json,text/vtt" aria-label="Load a transcript for {a.name ?? a.id}" class="w-40 text-[10px]" onchange={(e) => void load(a.id, e.currentTarget.files?.[0])} />
|
|
128
|
+
</li>
|
|
129
|
+
{/each}
|
|
130
|
+
</ul>
|
|
131
|
+
</details>
|
|
132
|
+
{/if}
|
|
133
|
+
{#if message}
|
|
134
|
+
<p class="text-red-500" role="alert" data-transcript-error="">{message}</p>
|
|
135
|
+
{/if}
|
|
136
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type VideoEditorController } from '@pixerate/editor/video-editor';
|
|
2
|
+
interface Props {
|
|
3
|
+
controller: VideoEditorController;
|
|
4
|
+
/** Track whose words to show (default: the first audio track with a transcribed clip, else the first video track with one). */
|
|
5
|
+
track?: string;
|
|
6
|
+
/** Allow cutting by text and loading transcripts (default true). */
|
|
7
|
+
editable?: boolean;
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const TranscriptPanel: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type TranscriptPanel = ReturnType<typeof TranscriptPanel>;
|
|
12
|
+
export default TranscriptPanel;
|
|
13
|
+
//# sourceMappingURL=TranscriptPanel.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TranscriptPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/TranscriptPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAQH,KAAK,qBAAqB,EAE3B,MAAM,+BAA+B,CAAC;AAIvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,+HAA+H;IAC/H,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqGH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { VideoEditorController, type VideoEditorOptions } from '@pixerate/editor/video-editor';
|
|
4
4
|
import ClipInspector from './ClipInspector.svelte';
|
|
5
5
|
import MediaBin from './MediaBin.svelte';
|
|
6
|
+
import TranscriptPanel from './TranscriptPanel.svelte';
|
|
6
7
|
import VideoPreview from './VideoPreview.svelte';
|
|
7
8
|
import VideoTimeline from './VideoTimeline.svelte';
|
|
8
9
|
import VideoTransport from './VideoTransport.svelte';
|
|
@@ -22,10 +23,12 @@
|
|
|
22
23
|
pxPerSecond?: number;
|
|
23
24
|
/** List the project's issues under the timeline (default true). */
|
|
24
25
|
showIssues?: boolean;
|
|
26
|
+
/** Show the transcript panel for editing by text (default true). */
|
|
27
|
+
showTranscript?: boolean;
|
|
25
28
|
class?: string;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
let { controller, options, editable = true, pxPerSecond = $bindable(100), showIssues = true, class: className = '' }: Props = $props();
|
|
31
|
+
let { controller, options, editable = true, pxPerSecond = $bindable(100), showIssues = true, showTranscript = true, class: className = '' }: Props = $props();
|
|
29
32
|
let owned: VideoEditorController | null = null;
|
|
30
33
|
// A controller is made only when none is passed, and kept for the component's lifetime.
|
|
31
34
|
const ctl = $derived(controller ?? (owned ??= new VideoEditorController(options)));
|
|
@@ -54,6 +57,7 @@
|
|
|
54
57
|
<VideoPreview controller={ctl} class="rounded-md" />
|
|
55
58
|
<VideoTransport controller={ctl} editable={false} />
|
|
56
59
|
<VideoTimeline controller={ctl} bind:pxPerSecond editable={false} />
|
|
60
|
+
{#if showTranscript}<TranscriptPanel controller={ctl} editable={false} />{/if}
|
|
57
61
|
{@render issueList()}
|
|
58
62
|
</div>
|
|
59
63
|
{:else}
|
|
@@ -66,6 +70,7 @@
|
|
|
66
70
|
<ClipInspector controller={ctl} class="min-w-0" />
|
|
67
71
|
<div class="flex min-w-0 flex-col gap-2 lg:col-span-3">
|
|
68
72
|
<VideoTimeline controller={ctl} bind:pxPerSecond />
|
|
73
|
+
{#if showTranscript}<TranscriptPanel controller={ctl} />{/if}
|
|
69
74
|
{@render issueList()}
|
|
70
75
|
</div>
|
|
71
76
|
</div>
|
|
@@ -13,6 +13,8 @@ interface Props {
|
|
|
13
13
|
pxPerSecond?: number;
|
|
14
14
|
/** List the project's issues under the timeline (default true). */
|
|
15
15
|
showIssues?: boolean;
|
|
16
|
+
/** Show the transcript panel for editing by text (default true). */
|
|
17
|
+
showTranscript?: boolean;
|
|
16
18
|
class?: string;
|
|
17
19
|
}
|
|
18
20
|
declare const VideoEditor: import("svelte").Component<Props, {}, "pxPerSecond">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/VideoEditor.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/video-editor/VideoEditor.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAU7F,UAAU,KAAK;IACb,2FAA2F;IAC3F,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2DH,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -5,12 +5,14 @@ import type VideoTransportComponent from "./VideoTransport.svelte";
|
|
|
5
5
|
import type VideoTimelineComponent from "./VideoTimeline.svelte";
|
|
6
6
|
import type ClipInspectorComponent from "./ClipInspector.svelte";
|
|
7
7
|
import type MediaBinComponent from "./MediaBin.svelte";
|
|
8
|
+
import type TranscriptPanelComponent from "./TranscriptPanel.svelte";
|
|
8
9
|
export { default as VideoEditor } from "./VideoEditor.svelte";
|
|
9
10
|
export { default as VideoPreview } from "./VideoPreview.svelte";
|
|
10
11
|
export { default as VideoTransport } from "./VideoTransport.svelte";
|
|
11
12
|
export { default as VideoTimeline } from "./VideoTimeline.svelte";
|
|
12
13
|
export { default as ClipInspector } from "./ClipInspector.svelte";
|
|
13
14
|
export { default as MediaBin } from "./MediaBin.svelte";
|
|
15
|
+
export { default as TranscriptPanel } from "./TranscriptPanel.svelte";
|
|
14
16
|
export * from "./createVideoEditor.svelte.js";
|
|
15
17
|
export type VideoEditorProps = ComponentProps<typeof VideoEditorComponent>;
|
|
16
18
|
export type VideoPreviewProps = ComponentProps<typeof VideoPreviewComponent>;
|
|
@@ -18,4 +20,5 @@ export type VideoTransportProps = ComponentProps<typeof VideoTransportComponent>
|
|
|
18
20
|
export type VideoTimelineProps = ComponentProps<typeof VideoTimelineComponent>;
|
|
19
21
|
export type ClipInspectorProps = ComponentProps<typeof ClipInspectorComponent>;
|
|
20
22
|
export type MediaBinProps = ComponentProps<typeof MediaBinComponent>;
|
|
23
|
+
export type TranscriptPanelProps = ComponentProps<typeof TranscriptPanelComponent>;
|
|
21
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/video-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/video-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AAErE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,cAAc,+BAA+B,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACjF,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACrE,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -4,4 +4,5 @@ export { default as VideoTransport } from "./VideoTransport.svelte";
|
|
|
4
4
|
export { default as VideoTimeline } from "./VideoTimeline.svelte";
|
|
5
5
|
export { default as ClipInspector } from "./ClipInspector.svelte";
|
|
6
6
|
export { default as MediaBin } from "./MediaBin.svelte";
|
|
7
|
+
export { default as TranscriptPanel } from "./TranscriptPanel.svelte";
|
|
7
8
|
export * from "./createVideoEditor.svelte.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"@tiptap/extension-bubble-menu": "^2.11.5",
|
|
132
132
|
"@tiptap/extension-placeholder": "^2.11.5",
|
|
133
133
|
"@tiptap/starter-kit": "^2.11.5",
|
|
134
|
-
"@pixerate/editor": "0.
|
|
134
|
+
"@pixerate/editor": "0.85.0"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"@dagrejs/dagre": "^1.1.4",
|