summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/timeline/placement/insert-index.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-03-31 15:53:23 +0200
committerMaze Winther <mazewinther@gmail.com>2026-03-31 15:53:23 +0200
commitd23be079cce6108482fc3e85401cccf949087174 (patch)
tree7d5acd324f9274b3b823bc67154349b8693e3412 /apps/web/src/lib/timeline/placement/insert-index.ts
parentdcf54c1250431f5a4a2848f7c07781ef5eebacaf (diff)
parent70a6d58b8432e455ab1443d45bc23dd70b363bea (diff)
downloadopencut-d23be079cce6108482fc3e85401cccf949087174.tar.gz
Merge branch 'feature/track-placement'
Diffstat (limited to 'apps/web/src/lib/timeline/placement/insert-index.ts')
-rw-r--r--apps/web/src/lib/timeline/placement/insert-index.ts99
1 files changed, 99 insertions, 0 deletions
diff --git a/apps/web/src/lib/timeline/placement/insert-index.ts b/apps/web/src/lib/timeline/placement/insert-index.ts
new file mode 100644
index 00000000..fecb893a
--- /dev/null
+++ b/apps/web/src/lib/timeline/placement/insert-index.ts
@@ -0,0 +1,99 @@
+import type { TrackType, TimelineTrack } from "@/lib/timeline";
+import { isMainTrack } from "./main-track";
+
+export function getDefaultInsertIndexForTrack({
+ tracks,
+ trackType,
+}: {
+ tracks: TimelineTrack[];
+ trackType: TrackType;
+}): number {
+ if (trackType === "audio") {
+ return tracks.length;
+ }
+
+ if (trackType === "effect") {
+ return 0;
+ }
+
+ const mainTrackIndex = tracks.findIndex((track) => isMainTrack(track));
+ if (mainTrackIndex >= 0) {
+ return mainTrackIndex;
+ }
+
+ const firstAudioTrackIndex = tracks.findIndex((track) => track.type === "audio");
+ if (firstAudioTrackIndex >= 0) {
+ return firstAudioTrackIndex;
+ }
+
+ return tracks.length;
+}
+
+export function getHighestInsertIndexForTrack({
+ tracks,
+ trackType,
+}: {
+ tracks: TimelineTrack[];
+ trackType: TrackType;
+}): number {
+ const mainTrackIndex = tracks.findIndex((track) => isMainTrack(track));
+ if (trackType === "audio") {
+ return mainTrackIndex >= 0 ? mainTrackIndex + 1 : tracks.length;
+ }
+
+ return 0;
+}
+
+export function resolvePreferredNewTrackPlacement({
+ tracks,
+ trackType,
+ preferredIndex,
+ direction,
+}: {
+ tracks: TimelineTrack[];
+ trackType: TrackType;
+ preferredIndex: number;
+ direction: "above" | "below";
+}): { insertIndex: number; insertPosition: "above" | "below" | null } {
+ if (tracks.length === 0) {
+ return {
+ insertIndex: 0,
+ insertPosition: trackType === "audio" ? "below" : null,
+ };
+ }
+
+ const safePreferredIndex = Math.min(
+ Math.max(preferredIndex, 0),
+ tracks.length - 1,
+ );
+ const mainTrackIndex = tracks.findIndex((track) => isMainTrack(track));
+
+ if (trackType === "audio") {
+ if (safePreferredIndex <= mainTrackIndex) {
+ return {
+ insertIndex: mainTrackIndex + 1,
+ insertPosition: "below",
+ };
+ }
+
+ return {
+ insertIndex:
+ direction === "above" ? safePreferredIndex : safePreferredIndex + 1,
+ insertPosition: direction,
+ };
+ }
+
+ const insertIndex =
+ direction === "above" ? safePreferredIndex : safePreferredIndex + 1;
+ if (mainTrackIndex >= 0 && insertIndex > mainTrackIndex) {
+ return {
+ insertIndex: mainTrackIndex,
+ insertPosition: "above",
+ };
+ }
+
+ return {
+ insertIndex,
+ insertPosition: direction,
+ };
+}