summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/timeline
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-08-26 15:04:25 +0200
committerMaze Winther <mazewinther@gmail.com>2025-08-26 15:04:25 +0200
commitb459b46802a760a4a81ce91fdf24390e07375fb0 (patch)
treee0070578d2b57acfba5f119cbf1abc6c9db5e741 /apps/web/src/components/editor/timeline
parent2f7cd11ca123884969f90a94e59593d355518839 (diff)
downloadopencut-b459b46802a760a4a81ce91fdf24390e07375fb0.tar.gz
refactor: type-safety & separate concerns
Diffstat (limited to 'apps/web/src/components/editor/timeline')
-rw-r--r--apps/web/src/components/editor/timeline/index.tsx30
-rw-r--r--apps/web/src/components/editor/timeline/timeline-element.tsx10
-rw-r--r--apps/web/src/components/editor/timeline/timeline-track.tsx36
3 files changed, 24 insertions, 52 deletions
diff --git a/apps/web/src/components/editor/timeline/index.tsx b/apps/web/src/components/editor/timeline/index.tsx
index 284384eb..49769989 100644
--- a/apps/web/src/components/editor/timeline/index.tsx
+++ b/apps/web/src/components/editor/timeline/index.tsx
@@ -82,13 +82,11 @@ export function Timeline() {
toggleTrackMute,
dragState,
} = useTimelineStore();
- const { mediaItems, addMediaItem } = useMediaStore();
+ const { mediaFiles, addMediaFile } = useMediaStore();
const { activeProject } = useProjectStore();
- const { currentTime, duration, seek, setDuration, isPlaying, toggle } =
- usePlaybackStore();
+ const { currentTime, duration, seek, setDuration } = usePlaybackStore();
const [isDragOver, setIsDragOver] = useState(false);
- const [isProcessing, setIsProcessing] = useState(false);
- const [progress, setProgress] = useState(0);
+ const { addElementToNewTrack } = useTimelineStore();
const dragCounterRef = useRef(0);
const timelineRef = useRef<HTMLDivElement>(null);
const rulerRef = useRef<HTMLDivElement>(null);
@@ -456,10 +454,10 @@ export function Timeline() {
if (dragData.type === "text") {
// Always create new text track to avoid overlaps
- useTimelineStore.getState().addTextToNewTrack(dragData);
+ addElementToNewTrack(dragData);
} else {
// Handle media items
- const mediaItem = mediaItems.find(
+ const mediaItem = mediaFiles.find(
(item: any) => item.id === dragData.id
);
if (!mediaItem) {
@@ -467,7 +465,7 @@ export function Timeline() {
return;
}
- useTimelineStore.getState().addMediaToNewTrack(mediaItem);
+ addElementToNewTrack(mediaItem);
}
} catch (error) {
console.error("Error parsing dropped item data:", error);
@@ -480,17 +478,12 @@ export function Timeline() {
return;
}
- setIsProcessing(true);
- setProgress(0);
try {
- const processedItems = await processMediaFiles(
- e.dataTransfer.files,
- (p) => setProgress(p)
- );
+ const processedItems = await processMediaFiles(e.dataTransfer.files);
for (const processedItem of processedItems) {
- await addMediaItem(activeProject.id, processedItem);
- const currentMediaItems = useMediaStore.getState().mediaItems;
- const addedItem = currentMediaItems.find(
+ await addMediaFile(activeProject.id, processedItem);
+ const currentMediaFiles = mediaFiles;
+ const addedItem = currentMediaFiles.find(
(item) =>
item.name === processedItem.name && item.url === processedItem.url
);
@@ -516,9 +509,6 @@ export function Timeline() {
// Show error if file processing fails
console.error("Error processing external files:", error);
toast.error("Failed to process dropped files");
- } finally {
- setIsProcessing(false);
- setProgress(0);
}
}
};
diff --git a/apps/web/src/components/editor/timeline/timeline-element.tsx b/apps/web/src/components/editor/timeline/timeline-element.tsx
index a1a33837..300c4c7b 100644
--- a/apps/web/src/components/editor/timeline/timeline-element.tsx
+++ b/apps/web/src/components/editor/timeline/timeline-element.tsx
@@ -40,10 +40,8 @@ export function TimelineElement({
onElementMouseDown,
onElementClick,
}: TimelineElementProps) {
- const { mediaItems } = useMediaStore();
+ const { mediaFiles } = useMediaStore();
const {
- updateElementTrim,
- updateElementDuration,
removeElementFromTrack,
removeElementFromTrackWithRipple,
dragState,
@@ -58,7 +56,7 @@ export function TimelineElement({
const mediaItem =
element.type === "media"
- ? mediaItems.find((item) => item.id === element.mediaId)
+ ? mediaFiles.find((file) => file.id === element.mediaId)
: null;
const hasAudio = mediaItem?.type === "audio" || mediaItem?.type === "video";
@@ -67,8 +65,6 @@ export function TimelineElement({
element,
track,
zoomLevel,
- onUpdateTrim: updateElementTrim,
- onUpdateDuration: updateElementDuration,
});
const { requestRevealMedia } = useMediaPanelStore.getState();
@@ -190,7 +186,7 @@ export function TimelineElement({
}
// Render media element ->
- const mediaItem = mediaItems.find((item) => item.id === element.mediaId);
+ const mediaItem = mediaFiles.find((file) => file.id === element.mediaId);
if (!mediaItem) {
return (
<span className="text-xs text-foreground/80 truncate">
diff --git a/apps/web/src/components/editor/timeline/timeline-track.tsx b/apps/web/src/components/editor/timeline/timeline-track.tsx
index 5a037710..ad3ca9b7 100644
--- a/apps/web/src/components/editor/timeline/timeline-track.tsx
+++ b/apps/web/src/components/editor/timeline/timeline-track.tsx
@@ -12,6 +12,7 @@ import {
canElementGoOnTrack,
} from "@/types/timeline";
import { usePlaybackStore } from "@/stores/playback-store";
+import { DEFAULT_TEXT_ELEMENT } from "@/constants/text-constants";
import type {
TimelineElement as TimelineElementType,
DragData,
@@ -33,7 +34,7 @@ export function TimelineTrackContent({
zoomLevel: number;
onSnapPointChange?: (snapPoint: SnapPoint | null) => void;
}) {
- const { mediaItems } = useMediaStore();
+ const { mediaFiles } = useMediaStore();
const {
tracks,
addTrack,
@@ -537,7 +538,7 @@ export function TimelineTrackContent({
});
} else {
// Media elements
- const mediaItem = mediaItems.find(
+ const mediaItem = mediaFiles.find(
(item) => item.id === dragData.id
);
if (mediaItem) {
@@ -890,29 +891,14 @@ export function TimelineTrackContent({
}
addElementToTrack(targetTrackId, {
- type: "text",
- name: dragData.name || "Text",
- content: dragData.content || "Default Text",
- duration: TIMELINE_CONSTANTS.DEFAULT_TEXT_DURATION,
+ ...DEFAULT_TEXT_ELEMENT,
+ name: dragData.name || DEFAULT_TEXT_ELEMENT.name,
+ content: dragData.content || DEFAULT_TEXT_ELEMENT.content,
startTime: textSnappedTime,
- trimStart: 0,
- trimEnd: 0,
- fontSize: 48,
- fontFamily: "Arial",
- color: "#ffffff",
- backgroundColor: "transparent",
- textAlign: "center",
- fontWeight: "normal",
- fontStyle: "normal",
- textDecoration: "none",
- x: 0,
- y: 0,
- rotation: 0,
- opacity: 1,
});
} else {
// Handle media items
- const mediaItem = mediaItems.find((item) => item.id === dragData.id);
+ const mediaItem = mediaFiles.find((item) => item.id === dragData.id);
if (!mediaItem) {
toast.error("Media item not found");
@@ -1054,7 +1040,7 @@ export function TimelineTrackContent({
} else if (hasFiles) {
// External file drops
const { activeProject } = useProjectStore.getState();
- const { addMediaItem } = useMediaStore.getState();
+ const { addMediaFile } = useMediaStore.getState();
const { addElementToTrack } = useTimelineStore.getState();
if (!activeProject) {
@@ -1066,9 +1052,9 @@ export function TimelineTrackContent({
processMediaFiles(e.dataTransfer.files)
.then(async (processedItems) => {
for (const processedItem of processedItems) {
- await addMediaItem(activeProject.id, processedItem);
- const currentMediaItems = useMediaStore.getState().mediaItems;
- const addedItem = currentMediaItems.find(
+ await addMediaFile(activeProject.id, processedItem);
+ const currentMediaFiles = mediaFiles;
+ const addedItem = currentMediaFiles.find(
(item) =>
item.name === processedItem.name &&
item.url === processedItem.url