summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/panels/timeline/timeline-element.tsx
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-03-31 23:23:36 +0200
committerMaze Winther <mazewinther@gmail.com>2026-03-31 23:23:36 +0200
commitf1d5932c54178c4f8eac61d3d3e0e4a30101780f (patch)
tree73ebf833517b1f0a9925151a703f335bedf49216 /apps/web/src/components/editor/panels/timeline/timeline-element.tsx
parentd23be079cce6108482fc3e85401cccf949087174 (diff)
downloadopencut-f1d5932c54178c4f8eac61d3d3e0e4a30101780f.tar.gz
feat: separate audio from elements
Diffstat (limited to 'apps/web/src/components/editor/panels/timeline/timeline-element.tsx')
-rw-r--r--apps/web/src/components/editor/panels/timeline/timeline-element.tsx35
1 files changed, 35 insertions, 0 deletions
diff --git a/apps/web/src/components/editor/panels/timeline/timeline-element.tsx b/apps/web/src/components/editor/panels/timeline/timeline-element.tsx
index f196da44..bb30b0b0 100644
--- a/apps/web/src/components/editor/panels/timeline/timeline-element.tsx
+++ b/apps/web/src/components/editor/panels/timeline/timeline-element.tsx
@@ -40,6 +40,11 @@ import type {
import type { MediaAsset } from "@/lib/media/types";
import { mediaSupportsAudio } from "@/lib/media/media-utils";
import {
+ canToggleSourceAudio,
+ getSourceAudioActionLabel,
+ isSourceAudioSeparated,
+} from "@/lib/timeline/audio-separation";
+import {
getActionDefinition,
type TAction,
type TActionWithOptionalArgs,
@@ -61,7 +66,9 @@ import {
Search01Icon,
Exchange01Icon,
KeyframeIcon,
+ Link02Icon,
MagicWand05Icon,
+ Unlink02Icon,
} from "@hugeicons/core-free-icons";
import { HugeiconsIcon } from "@hugeicons/react";
import { uppercase } from "@/utils/string";
@@ -280,6 +287,19 @@ export function TimelineElement({
};
const isMuted = canElementHaveAudio(element) && element.muted === true;
+ const canToggleCurrentSourceAudio =
+ selectedElements.length === 1 &&
+ isCurrentElementSelected &&
+ canToggleSourceAudio({
+ element,
+ mediaAsset,
+ });
+ const sourceAudioLabel =
+ element.type === "video"
+ ? getSourceAudioActionLabel({ element })
+ : "Extract audio";
+ const isElementSourceAudioSeparated =
+ element.type === "video" && isSourceAudioSeparated({ element });
return (
<ContextMenu>
@@ -334,6 +354,21 @@ export function TimelineElement({
isMuted={isMuted}
/>
)}
+ {canToggleCurrentSourceAudio && (
+ <ContextMenuItem
+ icon={
+ <HugeiconsIcon
+ icon={isElementSourceAudioSeparated ? Unlink02Icon : Link02Icon}
+ />
+ }
+ onClick={(event: React.MouseEvent) => {
+ event.stopPropagation();
+ invokeAction("toggle-source-audio");
+ }}
+ >
+ {sourceAudioLabel}
+ </ContextMenuItem>
+ )}
{canElementBeHidden(element) && (
<VisibilityMenuItem
element={element}