@r2digisolutions/components 0.2.0 → 0.3.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/components/atoms/Playhead/Playhead.svelte +44 -5
- package/dist/components/atoms/Playhead/Playhead.svelte.d.ts +8 -0
- package/dist/components/atoms/TimeRuler/TimeRuler.svelte +75 -16
- package/dist/components/atoms/TimeRuler/TimeRuler.svelte.d.ts +7 -0
- package/dist/components/atoms/TimelineGrid/TimelineGrid.stories.js +8 -0
- package/dist/components/atoms/TimelineGrid/TimelineGrid.svelte +39 -0
- package/dist/components/atoms/TimelineGrid/TimelineGrid.svelte.d.ts +11 -0
- package/dist/components/atoms/TimelineGrid/TimelineGridStory.svelte +7 -0
- package/dist/components/atoms/TimelineGrid/TimelineGridStory.svelte.d.ts +18 -0
- package/dist/components/molecules/ColorPicker/ColorPicker.svelte +45 -4
- package/dist/components/molecules/ColorPicker/ColorPicker.svelte.d.ts +2 -0
- package/dist/components/molecules/ContextMenu/ContextMenu.svelte +38 -11
- package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte +17 -2
- package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte.d.ts +5 -0
- package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte +362 -52
- package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte.d.ts +22 -2
- package/dist/components/molecules/PdfViewer/PdfViewer.svelte.d.ts +1 -1
- package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte +751 -29
- package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte.d.ts +14 -1
- package/dist/components/molecules/SplitPane/SplitPane.svelte +2 -2
- package/dist/components/molecules/TimelineClip/TimelineClip.svelte +95 -18
- package/dist/components/molecules/TimelineClip/TimelineClip.svelte.d.ts +3 -0
- package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte +82 -12
- package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte.d.ts +13 -2
- package/dist/components/molecules/TransportControls/TransportControls.svelte +84 -2
- package/dist/components/molecules/TransportControls/TransportControls.svelte.d.ts +13 -1
- package/dist/components/molecules/TransportControls/TransportControlsStory.svelte +33 -11
- package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.stories.js +8 -0
- package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.svelte +213 -0
- package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.svelte.d.ts +22 -0
- package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanelStory.svelte +7 -0
- package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanelStory.svelte.d.ts +18 -0
- package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.stories.js +8 -0
- package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.svelte +524 -0
- package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.svelte.d.ts +32 -0
- package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanelStory.svelte +7 -0
- package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanelStory.svelte.d.ts +18 -0
- package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte +85 -32
- package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte.d.ts +6 -0
- package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.stories.js +8 -0
- package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.svelte +113 -0
- package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.svelte.d.ts +18 -0
- package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanelStory.svelte +7 -0
- package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanelStory.svelte.d.ts +18 -0
- package/dist/components/organisms/AudioEditor/AudioEditor.svelte +52 -1
- package/dist/components/organisms/EditorShell/EditorShell.svelte +102 -92
- package/dist/components/organisms/FileUploader/FileUploader.stories.d.ts +10 -0
- package/dist/components/organisms/FileUploader/FileUploader.stories.js +21 -0
- package/dist/components/organisms/FileUploader/FileUploader.svelte +61 -21
- package/dist/components/organisms/FileUploader/FileUploader.svelte.d.ts +9 -0
- package/dist/components/organisms/FileUploader/FileUploaderStory.svelte +7 -1
- package/dist/components/organisms/FileUploader/FileUploaderStory.svelte.d.ts +3 -0
- package/dist/components/organisms/VideoEditor/VideoEditor.svelte +1457 -78
- package/dist/components/organisms/VideoEditor/VideoEditor.svelte.d.ts +2 -1
- package/dist/components/organisms/VideoEditor/VideoEditorStory.svelte +3 -2
- package/dist/index.d.ts +11 -3
- package/dist/index.js +6 -2
- package/dist/utils/mediaTime.d.ts +14 -4
- package/dist/utils/mediaTime.js +27 -8
- package/dist/utils/mediaTracks.d.ts +154 -0
- package/dist/utils/mediaTracks.js +697 -1
- package/dist/utils/videoSequence.js +35 -4
- package/package.json +1 -1
|
@@ -6,54 +6,107 @@
|
|
|
6
6
|
import Lock from '@lucide/svelte/icons/lock';
|
|
7
7
|
import LockOpen from '@lucide/svelte/icons/lock-open';
|
|
8
8
|
import Headphones from '@lucide/svelte/icons/headphones';
|
|
9
|
+
import GripVertical from '@lucide/svelte/icons/grip-vertical';
|
|
10
|
+
import Trash2 from '@lucide/svelte/icons/trash-2';
|
|
9
11
|
|
|
10
12
|
interface VideoTrackHeaderProps {
|
|
11
13
|
track: MediaTrack;
|
|
12
14
|
class?: string;
|
|
15
|
+
draggable?: boolean;
|
|
16
|
+
canRemove?: boolean;
|
|
17
|
+
dragging?: boolean;
|
|
13
18
|
onchange?: (track: MediaTrack) => void;
|
|
19
|
+
onremove?: (trackId: string) => void;
|
|
20
|
+
/** Pointer-based reorder (preferred over HTML5 drag) */
|
|
21
|
+
onreorderstart?: (trackId: string, e: PointerEvent) => void;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
|
-
let {
|
|
24
|
+
let {
|
|
25
|
+
track,
|
|
26
|
+
class: className = '',
|
|
27
|
+
draggable = false,
|
|
28
|
+
canRemove = false,
|
|
29
|
+
dragging = false,
|
|
30
|
+
onchange,
|
|
31
|
+
onremove,
|
|
32
|
+
onreorderstart
|
|
33
|
+
}: VideoTrackHeaderProps = $props();
|
|
17
34
|
|
|
18
35
|
function patch(partial: Partial<MediaTrack>) {
|
|
19
36
|
onchange?.({ ...track, ...partial });
|
|
20
37
|
}
|
|
21
38
|
</script>
|
|
22
39
|
|
|
23
|
-
<div class={['flex min-w-0 flex-1 items-center gap-1', className]}>
|
|
40
|
+
<div class={['flex min-w-0 flex-1 items-center gap-1', className, dragging && 'pointer-events-none']}>
|
|
41
|
+
{#if draggable}
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
class="flex h-6 w-5 shrink-0 cursor-grab touch-none items-center justify-center rounded text-muted hover:bg-surface-overlay hover:text-secondary active:cursor-grabbing"
|
|
45
|
+
aria-label={`Reorder ${track.name}`}
|
|
46
|
+
title="Drag to reorder"
|
|
47
|
+
data-marquee-ignore
|
|
48
|
+
onpointerdown={(e) => {
|
|
49
|
+
if (e.button !== 0) return;
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
e.stopPropagation();
|
|
52
|
+
onreorderstart?.(track.id, e);
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
<GripVertical class="h-3.5 w-3.5" />
|
|
56
|
+
</button>
|
|
57
|
+
{/if}
|
|
24
58
|
<span
|
|
25
59
|
class="h-2 w-2 shrink-0 rounded-full"
|
|
26
60
|
style:background={track.color ?? (track.kind === 'audio' ? '#10b981' : '#3b82f6')}
|
|
27
61
|
aria-hidden="true"
|
|
28
62
|
></span>
|
|
29
|
-
<span class="min-w-0 flex-1 truncate text-xs font-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
<span class="min-w-0 flex-1 truncate text-xs font-semibold text-primary" title={track.name}>
|
|
64
|
+
{track.name}
|
|
65
|
+
</span>
|
|
66
|
+
{#if !dragging}
|
|
67
|
+
<div class="flex shrink-0 items-center">
|
|
68
|
+
<IconButton
|
|
69
|
+
label={track.muted ? 'Unmute' : 'Mute'}
|
|
70
|
+
size="xs"
|
|
71
|
+
class="!h-5 !w-5"
|
|
72
|
+
onclick={() => patch({ muted: !track.muted })}
|
|
73
|
+
>
|
|
74
|
+
{#if track.muted}
|
|
75
|
+
<VolumeX class="h-3 w-3" />
|
|
76
|
+
{:else}
|
|
77
|
+
<Volume2 class="h-3 w-3" />
|
|
78
|
+
{/if}
|
|
79
|
+
</IconButton>
|
|
80
|
+
<IconButton
|
|
81
|
+
label={track.solo ? 'Unsolo' : 'Solo'}
|
|
82
|
+
size="xs"
|
|
83
|
+
class="!h-5 !w-5"
|
|
84
|
+
onclick={() => patch({ solo: !track.solo })}
|
|
85
|
+
>
|
|
86
|
+
<Headphones class={['h-3 w-3', track.solo && 'text-brand-500']} />
|
|
87
|
+
</IconButton>
|
|
88
|
+
<IconButton
|
|
89
|
+
label={track.locked ? 'Unlock' : 'Lock'}
|
|
90
|
+
size="xs"
|
|
91
|
+
class="!h-5 !w-5"
|
|
92
|
+
onclick={() => patch({ locked: !track.locked })}
|
|
93
|
+
>
|
|
94
|
+
{#if track.locked}
|
|
95
|
+
<Lock class="h-3 w-3" />
|
|
96
|
+
{:else}
|
|
97
|
+
<LockOpen class="h-3 w-3" />
|
|
98
|
+
{/if}
|
|
99
|
+
</IconButton>
|
|
100
|
+
{#if canRemove && onremove}
|
|
101
|
+
<IconButton
|
|
102
|
+
label="Delete track"
|
|
103
|
+
size="xs"
|
|
104
|
+
class="!h-5 !w-5"
|
|
105
|
+
onclick={() => onremove(track.id)}
|
|
106
|
+
>
|
|
107
|
+
<Trash2 class="h-3 w-3" />
|
|
108
|
+
</IconButton>
|
|
109
|
+
{/if}
|
|
110
|
+
</div>
|
|
111
|
+
{/if}
|
|
59
112
|
</div>
|
|
@@ -2,7 +2,13 @@ import type { MediaTrack } from '../../../utils/mediaTracks.js';
|
|
|
2
2
|
interface VideoTrackHeaderProps {
|
|
3
3
|
track: MediaTrack;
|
|
4
4
|
class?: string;
|
|
5
|
+
draggable?: boolean;
|
|
6
|
+
canRemove?: boolean;
|
|
7
|
+
dragging?: boolean;
|
|
5
8
|
onchange?: (track: MediaTrack) => void;
|
|
9
|
+
onremove?: (trackId: string) => void;
|
|
10
|
+
/** Pointer-based reorder (preferred over HTML5 drag) */
|
|
11
|
+
onreorderstart?: (trackId: string, e: PointerEvent) => void;
|
|
6
12
|
}
|
|
7
13
|
declare const VideoTrackHeader: import("svelte").Component<VideoTrackHeaderProps, {}, "">;
|
|
8
14
|
type VideoTrackHeader = ReturnType<typeof VideoTrackHeader>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export interface VideoTransitionDef {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
group: string;
|
|
6
|
+
type: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
glyph?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const VIDEO_TRANSITION_MIME = 'application/x-r2-video-transition';
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
interface VideoTransitionsPanelProps {
|
|
16
|
+
class?: string;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
hint?: string;
|
|
19
|
+
onapply?: (def: VideoTransitionDef) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
class: className = '',
|
|
24
|
+
disabled = false,
|
|
25
|
+
hint = 'Select a clip, or drag onto its end',
|
|
26
|
+
onapply
|
|
27
|
+
}: VideoTransitionsPanelProps = $props();
|
|
28
|
+
|
|
29
|
+
const transitions: VideoTransitionDef[] = [
|
|
30
|
+
/* Dissolve */
|
|
31
|
+
{ id: 'crossfade', label: 'Crossfade', group: 'Dissolve', type: 'crossfade', durationMs: 900, glyph: '╳' },
|
|
32
|
+
{ id: 'dip-black', label: 'Dip black', group: 'Dissolve', type: 'dip-black', durationMs: 1000, glyph: '■' },
|
|
33
|
+
{ id: 'dip-white', label: 'Dip white', group: 'Dissolve', type: 'dip-white', durationMs: 1000, glyph: '□' },
|
|
34
|
+
{ id: 'fade-soft', label: 'Soft fade', group: 'Dissolve', type: 'fade-soft', durationMs: 1200, glyph: '≈' },
|
|
35
|
+
{ id: 'blur-dissolve', label: 'Blur', group: 'Dissolve', type: 'blur', durationMs: 1000, glyph: '◈' },
|
|
36
|
+
{ id: 'flash', label: 'Flash', group: 'Dissolve', type: 'flash', durationMs: 500, glyph: '⚡' },
|
|
37
|
+
/* Wipe */
|
|
38
|
+
{ id: 'wipe-left', label: 'Wipe left', group: 'Wipe', type: 'wipe-left', durationMs: 900, glyph: '◀' },
|
|
39
|
+
{ id: 'wipe-right', label: 'Wipe right', group: 'Wipe', type: 'wipe-right', durationMs: 900, glyph: '▶' },
|
|
40
|
+
{ id: 'wipe-up', label: 'Wipe up', group: 'Wipe', type: 'wipe-up', durationMs: 900, glyph: '▲' },
|
|
41
|
+
{ id: 'wipe-down', label: 'Wipe down', group: 'Wipe', type: 'wipe-down', durationMs: 900, glyph: '▼' },
|
|
42
|
+
{ id: 'wipe-diagonal', label: 'Diagonal', group: 'Wipe', type: 'wipe-diagonal', durationMs: 900, glyph: '╱' },
|
|
43
|
+
{ id: 'iris', label: 'Iris', group: 'Wipe', type: 'iris', durationMs: 900, glyph: '◎' },
|
|
44
|
+
{ id: 'barn-doors', label: 'Barn doors', group: 'Wipe', type: 'barn-doors', durationMs: 900, glyph: ' ⟺ ' },
|
|
45
|
+
/* Move */
|
|
46
|
+
{ id: 'push-left', label: 'Push left', group: 'Move', type: 'push-left', durationMs: 900, glyph: '⇇' },
|
|
47
|
+
{ id: 'push-right', label: 'Push right', group: 'Move', type: 'push-right', durationMs: 900, glyph: '⇉' },
|
|
48
|
+
{ id: 'push-up', label: 'Push up', group: 'Move', type: 'push-up', durationMs: 900, glyph: '⇈' },
|
|
49
|
+
{ id: 'push-down', label: 'Push down', group: 'Move', type: 'push-down', durationMs: 900, glyph: '⇊' },
|
|
50
|
+
{ id: 'slide-left', label: 'Slide left', group: 'Move', type: 'slide-left', durationMs: 900, glyph: '◁' },
|
|
51
|
+
{ id: 'slide-right', label: 'Slide right', group: 'Move', type: 'slide-right', durationMs: 900, glyph: '▷' },
|
|
52
|
+
/* Style */
|
|
53
|
+
{ id: 'zoom-through', label: 'Zoom in', group: 'Style', type: 'zoom-in', durationMs: 900, glyph: '⊕' },
|
|
54
|
+
{ id: 'zoom-out', label: 'Zoom out', group: 'Style', type: 'zoom-out', durationMs: 900, glyph: '⊖' },
|
|
55
|
+
{ id: 'spin', label: 'Spin', group: 'Style', type: 'spin', durationMs: 900, glyph: '↻' },
|
|
56
|
+
{ id: 'flip-x', label: 'Flip H', group: 'Style', type: 'flip-x', durationMs: 900, glyph: '↔' },
|
|
57
|
+
{ id: 'flip-y', label: 'Flip V', group: 'Style', type: 'flip-y', durationMs: 900, glyph: '↕' },
|
|
58
|
+
{ id: 'squeeze-h', label: 'Squeeze H', group: 'Style', type: 'squeeze-h', durationMs: 800, glyph: '↔︎' },
|
|
59
|
+
{ id: 'squeeze-v', label: 'Squeeze V', group: 'Style', type: 'squeeze-v', durationMs: 800, glyph: '↕︎' }
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const groups = $derived(
|
|
63
|
+
[...new Set(transitions.map((t) => t.group))].map((group) => ({
|
|
64
|
+
group,
|
|
65
|
+
items: transitions.filter((t) => t.group === group)
|
|
66
|
+
}))
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
function onDragStart(e: DragEvent, item: VideoTransitionDef) {
|
|
70
|
+
if (disabled) {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
e.dataTransfer?.setData(VIDEO_TRANSITION_MIME, JSON.stringify(item));
|
|
75
|
+
e.dataTransfer?.setData('text/plain', item.label);
|
|
76
|
+
if (e.dataTransfer) e.dataTransfer.effectAllowed = 'copy';
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<div class={['flex flex-col gap-4 p-2', className]}>
|
|
81
|
+
{#if disabled}
|
|
82
|
+
<p class="px-1 py-4 text-center text-xs text-muted">{hint}</p>
|
|
83
|
+
{:else}
|
|
84
|
+
<p class="px-1 text-[10px] leading-relaxed text-muted">
|
|
85
|
+
CapCut-style: transition sits at the <strong class="font-medium text-secondary">end</strong> of
|
|
86
|
+
a clip (into the next). Drag onto a clip or click with one selected.
|
|
87
|
+
</p>
|
|
88
|
+
{/if}
|
|
89
|
+
{#each groups as { group, items } (group)}
|
|
90
|
+
<section class="flex flex-col gap-2">
|
|
91
|
+
<h3 class="px-1 text-[10px] font-semibold uppercase tracking-wide text-muted">{group}</h3>
|
|
92
|
+
<div class="grid grid-cols-3 gap-1.5">
|
|
93
|
+
{#each items as item (item.id)}
|
|
94
|
+
<button
|
|
95
|
+
type="button"
|
|
96
|
+
disabled={disabled}
|
|
97
|
+
draggable={!disabled}
|
|
98
|
+
ondragstart={(e) => onDragStart(e, item)}
|
|
99
|
+
class="flex cursor-grab flex-col items-center gap-1.5 rounded-lg border border-border bg-surface-elevated px-1.5 py-2 text-center transition-colors enabled:hover:border-brand-500/50 enabled:hover:bg-surface-overlay active:cursor-grabbing disabled:cursor-not-allowed disabled:opacity-50"
|
|
100
|
+
onclick={() => onapply?.(item)}
|
|
101
|
+
>
|
|
102
|
+
<span
|
|
103
|
+
class="flex h-9 w-full items-center justify-center rounded-md bg-surface text-sm font-semibold text-secondary"
|
|
104
|
+
>
|
|
105
|
+
{item.glyph ?? item.label.slice(0, 2)}
|
|
106
|
+
</span>
|
|
107
|
+
<span class="text-[10px] font-medium text-secondary">{item.label}</span>
|
|
108
|
+
</button>
|
|
109
|
+
{/each}
|
|
110
|
+
</div>
|
|
111
|
+
</section>
|
|
112
|
+
{/each}
|
|
113
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface VideoTransitionDef {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
group: string;
|
|
5
|
+
type: string;
|
|
6
|
+
durationMs: number;
|
|
7
|
+
glyph?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const VIDEO_TRANSITION_MIME = "application/x-r2-video-transition";
|
|
10
|
+
interface VideoTransitionsPanelProps {
|
|
11
|
+
class?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
hint?: string;
|
|
14
|
+
onapply?: (def: VideoTransitionDef) => void;
|
|
15
|
+
}
|
|
16
|
+
declare const VideoTransitionsPanel: import("svelte").Component<VideoTransitionsPanelProps, {}, "">;
|
|
17
|
+
type VideoTransitionsPanel = ReturnType<typeof VideoTransitionsPanel>;
|
|
18
|
+
export default VideoTransitionsPanel;
|
package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanelStory.svelte.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const VideoTransitionsPanelStory: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type VideoTransitionsPanelStory = InstanceType<typeof VideoTransitionsPanelStory>;
|
|
18
|
+
export default VideoTransitionsPanelStory;
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
let selectedClipId = $state<string | null>(null);
|
|
42
42
|
let currentTimeMs = $state(0);
|
|
43
43
|
let playing = $state(false);
|
|
44
|
+
let playbackRate = $state(1);
|
|
45
|
+
let muted = $state(false);
|
|
46
|
+
let volume = $state(1);
|
|
47
|
+
const SKIP_MS = 5000;
|
|
44
48
|
let zoom = $state(1);
|
|
45
49
|
let showSidebar = $state(true);
|
|
46
50
|
let showInspector = $state(true);
|
|
@@ -114,10 +118,14 @@
|
|
|
114
118
|
});
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
function seekBy(deltaMs: number) {
|
|
122
|
+
currentTimeMs = clampMs(currentTimeMs + deltaMs, 0, value.durationMs);
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
function tick(ts: number) {
|
|
118
126
|
if (!playing) return;
|
|
119
127
|
if (lastTs) {
|
|
120
|
-
const delta = ts - lastTs;
|
|
128
|
+
const delta = (ts - lastTs) * playbackRate;
|
|
121
129
|
currentTimeMs = clampMs(currentTimeMs + delta, 0, value.durationMs);
|
|
122
130
|
if (currentTimeMs >= value.durationMs) {
|
|
123
131
|
playing = false;
|
|
@@ -145,6 +153,36 @@
|
|
|
145
153
|
playing = !playing;
|
|
146
154
|
return;
|
|
147
155
|
}
|
|
156
|
+
if (e.key === 'Escape') {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
selectedClipId = null;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (e.key === 'ArrowLeft') {
|
|
162
|
+
e.preventDefault();
|
|
163
|
+
seekBy(e.shiftKey ? -SKIP_MS : -1000);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (e.key === 'ArrowRight') {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
seekBy(e.shiftKey ? SKIP_MS : 1000);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (e.key === 'Home') {
|
|
172
|
+
e.preventDefault();
|
|
173
|
+
currentTimeMs = 0;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (e.key === 'End') {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
currentTimeMs = value.durationMs;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (e.key === 'm' || e.key === 'M') {
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
muted = !muted;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
148
186
|
if ((e.key === 'Delete' || e.key === 'Backspace') && selectedClipId) {
|
|
149
187
|
e.preventDefault();
|
|
150
188
|
setTracks(removeClipFromTracks(value.tracks, selectedClipId));
|
|
@@ -231,12 +269,24 @@
|
|
|
231
269
|
{playing}
|
|
232
270
|
{currentTimeMs}
|
|
233
271
|
durationMs={value.durationMs}
|
|
272
|
+
bind:playbackRate
|
|
273
|
+
bind:muted
|
|
274
|
+
bind:volume
|
|
275
|
+
skipMs={SKIP_MS}
|
|
234
276
|
onplay={() => (playing = true)}
|
|
235
277
|
onpause={() => (playing = false)}
|
|
236
278
|
onstop={() => {
|
|
237
279
|
playing = false;
|
|
238
280
|
currentTimeMs = 0;
|
|
239
281
|
}}
|
|
282
|
+
onseekstart={() => {
|
|
283
|
+
currentTimeMs = 0;
|
|
284
|
+
}}
|
|
285
|
+
onseekend={() => {
|
|
286
|
+
currentTimeMs = value.durationMs;
|
|
287
|
+
}}
|
|
288
|
+
onseekback={() => seekBy(-SKIP_MS)}
|
|
289
|
+
onseekforward={() => seekBy(SKIP_MS)}
|
|
240
290
|
/>
|
|
241
291
|
<div class="min-h-0 flex-1">
|
|
242
292
|
<MediaTimeline
|
|
@@ -247,6 +297,7 @@
|
|
|
247
297
|
{selectedClipId}
|
|
248
298
|
headerVariant="audio"
|
|
249
299
|
onselectclip={(id) => (selectedClipId = id)}
|
|
300
|
+
onemptyclick={() => (selectedClipId = null)}
|
|
250
301
|
onchangeclip={patchClip}
|
|
251
302
|
onchangetrack={patchTrack}
|
|
252
303
|
onseek={(ms) => (currentTimeMs = ms)}
|
|
@@ -127,104 +127,114 @@
|
|
|
127
127
|
</div>
|
|
128
128
|
|
|
129
129
|
{#snippet mainAndInspector()}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{#
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
130
|
+
<div class="h-full min-h-0 min-w-0">
|
|
131
|
+
{#if showInspector}
|
|
132
|
+
<SplitPane
|
|
133
|
+
orientation="horizontal"
|
|
134
|
+
bind:size={inspectorSize}
|
|
135
|
+
sizePane="end"
|
|
136
|
+
unit={sizeUnit}
|
|
137
|
+
minSize={inspectorMin}
|
|
138
|
+
maxSize={inspectorMax}
|
|
139
|
+
endCollapsed={wrapInspector && inspectorCollapsed}
|
|
140
|
+
revealOnHover={revealResizeOnHover}
|
|
141
|
+
class="h-full"
|
|
142
|
+
>
|
|
143
|
+
{#snippet start()}
|
|
144
|
+
{@render centerColumn()}
|
|
145
|
+
{/snippet}
|
|
146
|
+
{#snippet end()}
|
|
147
|
+
{#if wrapInspector}
|
|
148
|
+
<Panel
|
|
149
|
+
title={inspectorTitle}
|
|
150
|
+
padding="none"
|
|
151
|
+
collapsible={collapsiblePanels}
|
|
152
|
+
bind:collapsed={inspectorCollapsed}
|
|
153
|
+
>
|
|
154
|
+
{#if inspector}
|
|
155
|
+
{@render inspector()}
|
|
156
|
+
{/if}
|
|
157
|
+
</Panel>
|
|
158
|
+
{:else if inspector}
|
|
159
|
+
<div class="h-full min-h-0 min-w-0">
|
|
154
160
|
{@render inspector()}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
{
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{@render centerColumn()}
|
|
164
|
-
{/if}
|
|
161
|
+
</div>
|
|
162
|
+
{/if}
|
|
163
|
+
{/snippet}
|
|
164
|
+
</SplitPane>
|
|
165
|
+
{:else}
|
|
166
|
+
{@render centerColumn()}
|
|
167
|
+
{/if}
|
|
168
|
+
</div>
|
|
165
169
|
{/snippet}
|
|
166
170
|
|
|
167
171
|
{#snippet centerColumn()}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
{#
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
172
|
+
<div class="h-full min-h-0 min-w-0">
|
|
173
|
+
{#if showBottom}
|
|
174
|
+
<SplitPane
|
|
175
|
+
orientation="vertical"
|
|
176
|
+
bind:size={bottomSize}
|
|
177
|
+
sizePane="end"
|
|
178
|
+
unit={sizeUnit}
|
|
179
|
+
minSize={bottomMin}
|
|
180
|
+
maxSize={bottomMax}
|
|
181
|
+
startCollapsed={wrapWorkspace && workspaceCollapsed}
|
|
182
|
+
endCollapsed={wrapBottom && bottomCollapsed}
|
|
183
|
+
revealOnHover={revealResizeOnHover}
|
|
184
|
+
class="h-full"
|
|
185
|
+
>
|
|
186
|
+
{#snippet start()}
|
|
187
|
+
{#if wrapWorkspace}
|
|
188
|
+
<Panel
|
|
189
|
+
title={workspaceTitle}
|
|
190
|
+
padding="none"
|
|
191
|
+
collapsible={collapsiblePanels}
|
|
192
|
+
bind:collapsed={workspaceCollapsed}
|
|
193
|
+
>
|
|
194
|
+
{#if workspace}
|
|
195
|
+
{@render workspace()}
|
|
196
|
+
{/if}
|
|
197
|
+
</Panel>
|
|
198
|
+
{:else if workspace}
|
|
199
|
+
<div class="h-full min-h-0 min-w-0">
|
|
190
200
|
{@render workspace()}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
{
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
</div>
|
|
202
|
+
{/if}
|
|
203
|
+
{/snippet}
|
|
204
|
+
{#snippet end()}
|
|
205
|
+
{#if wrapBottom}
|
|
206
|
+
<Panel
|
|
207
|
+
title={bottomTitle}
|
|
208
|
+
padding="none"
|
|
209
|
+
collapsible={collapsiblePanels}
|
|
210
|
+
bind:collapsed={bottomCollapsed}
|
|
211
|
+
>
|
|
212
|
+
{#if bottom}
|
|
213
|
+
{@render bottom()}
|
|
214
|
+
{/if}
|
|
215
|
+
</Panel>
|
|
216
|
+
{:else if bottom}
|
|
217
|
+
<div class="h-full min-h-0 min-w-0">
|
|
206
218
|
{@render bottom()}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
|
|
219
|
+
</div>
|
|
220
|
+
{/if}
|
|
221
|
+
{/snippet}
|
|
222
|
+
</SplitPane>
|
|
223
|
+
{:else if wrapWorkspace}
|
|
224
|
+
<Panel
|
|
225
|
+
title={workspaceTitle}
|
|
226
|
+
padding="none"
|
|
227
|
+
collapsible={collapsiblePanels}
|
|
228
|
+
bind:collapsed={workspaceCollapsed}
|
|
229
|
+
>
|
|
230
|
+
{#if workspace}
|
|
231
|
+
{@render workspace()}
|
|
211
232
|
{/if}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
<Panel
|
|
216
|
-
title={workspaceTitle}
|
|
217
|
-
padding="none"
|
|
218
|
-
collapsible={collapsiblePanels}
|
|
219
|
-
bind:collapsed={workspaceCollapsed}
|
|
220
|
-
>
|
|
221
|
-
{#if workspace}
|
|
233
|
+
</Panel>
|
|
234
|
+
{:else if workspace}
|
|
235
|
+
<div class="h-full min-h-0 min-w-0">
|
|
222
236
|
{@render workspace()}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
<div class="h-full min-h-0 min-w-0">
|
|
227
|
-
{@render workspace()}
|
|
228
|
-
</div>
|
|
229
|
-
{/if}
|
|
237
|
+
</div>
|
|
238
|
+
{/if}
|
|
239
|
+
</div>
|
|
230
240
|
{/snippet}
|
|
@@ -7,9 +7,12 @@ declare const meta: {
|
|
|
7
7
|
accept?: string;
|
|
8
8
|
variant?: "multiple" | "single" | "avatar";
|
|
9
9
|
view?: "list" | "grid";
|
|
10
|
+
layout?: "horizontal" | "vertical" | "compact";
|
|
10
11
|
showViewToggle?: boolean;
|
|
11
12
|
maxSizeMb?: number;
|
|
12
13
|
disabled?: boolean;
|
|
14
|
+
src?: string;
|
|
15
|
+
srcName?: string;
|
|
13
16
|
}, {}, "">;
|
|
14
17
|
tags: string[];
|
|
15
18
|
argTypes: {
|
|
@@ -30,6 +33,10 @@ declare const meta: {
|
|
|
30
33
|
control: "select";
|
|
31
34
|
options: string[];
|
|
32
35
|
};
|
|
36
|
+
layout: {
|
|
37
|
+
control: "select";
|
|
38
|
+
options: string[];
|
|
39
|
+
};
|
|
33
40
|
showViewToggle: {
|
|
34
41
|
control: "boolean";
|
|
35
42
|
};
|
|
@@ -46,6 +53,7 @@ declare const meta: {
|
|
|
46
53
|
accept: string;
|
|
47
54
|
variant: "multiple";
|
|
48
55
|
view: "list";
|
|
56
|
+
layout: "horizontal";
|
|
49
57
|
showViewToggle: true;
|
|
50
58
|
maxSizeMb: number;
|
|
51
59
|
disabled: false;
|
|
@@ -55,6 +63,8 @@ export default meta;
|
|
|
55
63
|
type Story = StoryObj<typeof meta>;
|
|
56
64
|
export declare const Multiple: Story;
|
|
57
65
|
export declare const GridView: Story;
|
|
66
|
+
export declare const VerticalSidebar: Story;
|
|
67
|
+
export declare const Compact: Story;
|
|
58
68
|
export declare const SingleFile: Story;
|
|
59
69
|
export declare const Avatar: Story;
|
|
60
70
|
export declare const Disabled: Story;
|