From fca99d6126c31fbb18ed9f1034cee6f940b040e8 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Tue, 10 Feb 2026 16:28:21 +0100 Subject: refactor --- .../editor/timeline/timeline-element.tsx | 554 --------------------- 1 file changed, 554 deletions(-) delete mode 100644 apps/web/src/components/editor/timeline/timeline-element.tsx (limited to 'apps/web/src/components/editor/timeline/timeline-element.tsx') diff --git a/apps/web/src/components/editor/timeline/timeline-element.tsx b/apps/web/src/components/editor/timeline/timeline-element.tsx deleted file mode 100644 index fd292ad8..00000000 --- a/apps/web/src/components/editor/timeline/timeline-element.tsx +++ /dev/null @@ -1,554 +0,0 @@ -"use client"; - -import { useEditor } from "@/hooks/use-editor"; -import { useAssetsPanelStore } from "@/stores/assets-panel-store"; -import AudioWaveform from "./audio-waveform"; -import { useTimelineElementResize } from "@/hooks/timeline/element/use-element-resize"; -import type { SnapPoint } from "@/hooks/timeline/use-timeline-snapping"; -import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants"; -import { - getTrackClasses, - getTrackHeight, - canElementHaveAudio, - canElementBeHidden, - hasMediaId, -} from "@/lib/timeline"; -import { - ContextMenu, - ContextMenuContent, - ContextMenuItem, - ContextMenuSeparator, - ContextMenuTrigger, -} from "../../ui/context-menu"; -import type { - TimelineElement as TimelineElementType, - TimelineTrack, - ElementDragState, -} from "@/types/timeline"; -import type { MediaAsset } from "@/types/assets"; -import { mediaSupportsAudio } from "@/lib/media/media-utils"; -import { getActionDefinition, type TAction, invokeAction } from "@/lib/actions"; -import { useElementSelection } from "@/hooks/timeline/element/use-element-selection"; -import Image from "next/image"; -import { - ScissorIcon, - Delete02Icon, - Copy01Icon, - ViewIcon, - ViewOffSlashIcon, - VolumeHighIcon, - VolumeOffIcon, - VolumeMute02Icon, - Search01Icon, - Exchange01Icon, -} from "@hugeicons/core-free-icons"; -import { HugeiconsIcon } from "@hugeicons/react"; -import { uppercase } from "@/utils/string"; -import type { ComponentProps } from "react"; - -function getDisplayShortcut(action: TAction) { - const { defaultShortcuts } = getActionDefinition(action); - if (!defaultShortcuts?.length) { - return ""; - } - - return uppercase({ - string: defaultShortcuts[0].replace("+", " "), - }); -} - -interface TimelineElementProps { - element: TimelineElementType; - track: TimelineTrack; - zoomLevel: number; - isSelected: boolean; - onSnapPointChange?: (snapPoint: SnapPoint | null) => void; - onResizeStateChange?: (params: { isResizing: boolean }) => void; - onElementMouseDown: ( - e: React.MouseEvent, - element: TimelineElementType, - ) => void; - onElementClick: (e: React.MouseEvent, element: TimelineElementType) => void; - dragState: ElementDragState; -} - -export function TimelineElement({ - element, - track, - zoomLevel, - isSelected, - onSnapPointChange, - onResizeStateChange, - onElementMouseDown, - onElementClick, - dragState, -}: TimelineElementProps) { - const editor = useEditor(); - const { selectedElements } = useElementSelection(); - const { requestRevealMedia } = useAssetsPanelStore(); - - const mediaAssets = editor.media.getAssets(); - let mediaAsset: MediaAsset | null = null; - - if (hasMediaId(element)) { - mediaAsset = - mediaAssets.find((asset) => asset.id === element.mediaId) ?? null; - } - - const hasAudio = mediaSupportsAudio({ media: mediaAsset }); - - const { handleResizeStart, isResizing, currentStartTime, currentDuration } = - useTimelineElementResize({ - element, - track, - zoomLevel, - onSnapPointChange, - onResizeStateChange, - }); - - const isCurrentElementSelected = selectedElements.some( - (selected) => - selected.elementId === element.id && selected.trackId === track.id, - ); - - const isBeingDragged = dragState.elementId === element.id; - const dragOffsetY = - isBeingDragged && dragState.isDragging - ? dragState.currentMouseY - dragState.startMouseY - : 0; - const elementStartTime = - isBeingDragged && dragState.isDragging - ? dragState.currentTime - : element.startTime; - const displayedStartTime = isResizing ? currentStartTime : elementStartTime; - const displayedDuration = isResizing ? currentDuration : element.duration; - const elementWidth = - displayedDuration * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel; - const elementLeft = displayedStartTime * 50 * zoomLevel; - - const handleRevealInMedia = ({ event }: { event: React.MouseEvent }) => { - event.stopPropagation(); - if (hasMediaId(element)) { - requestRevealMedia(element.mediaId); - } - }; - - const isMuted = canElementHaveAudio(element) && element.muted === true; - - return ( - - -
- -
-
- - }> - Split - - - {canElementHaveAudio(element) && hasAudio && ( - 1} - isCurrentElementSelected={isCurrentElementSelected} - isMuted={isMuted} - /> - )} - {canElementBeHidden(element) && ( - 1} - isCurrentElementSelected={isCurrentElementSelected} - /> - )} - {selectedElements.length === 1 && ( - }> - Duplicate - - )} - {selectedElements.length === 1 && hasMediaId(element) && ( - <> - } - onClick={(event) => handleRevealInMedia({ event })} - > - Reveal media - - } - disabled - > - Replace media - - - )} - - 1} - isCurrentElementSelected={isCurrentElementSelected} - elementType={element.type} - selectedCount={selectedElements.length} - /> - -
- ); -} - -function ElementInner({ - element, - track, - isSelected, - isBeingDragged, - hasAudio, - isMuted, - mediaAssets, - onElementClick, - onElementMouseDown, - handleResizeStart, -}: { - element: TimelineElementType; - track: TimelineTrack; - isSelected: boolean; - isBeingDragged: boolean; - hasAudio: boolean; - isMuted: boolean; - mediaAssets: MediaAsset[]; - onElementClick: (e: React.MouseEvent, element: TimelineElementType) => void; - onElementMouseDown: ( - e: React.MouseEvent, - element: TimelineElementType, - ) => void; - handleResizeStart: (params: { - e: React.MouseEvent; - elementId: string; - side: "left" | "right"; - }) => void; -}) { - return ( -
- - - {isSelected && ( - <> - - - - )} -
- ); -} - -function ResizeHandle({ - side, - elementId, - handleResizeStart, -}: { - side: "left" | "right"; - elementId: string; - handleResizeStart: (params: { - e: React.MouseEvent; - elementId: string; - side: "left" | "right"; - }) => void; -}) { - const isLeft = side === "left"; - return ( - - ); -} - -function ElementContent({ - element, - track, - isSelected, - mediaAssets, -}: { - element: TimelineElementType; - track: TimelineTrack; - isSelected: boolean; - mediaAssets: MediaAsset[]; -}) { - if (element.type === "text") { - return ( -
- {element.content} -
- ); - } - - if (element.type === "sticker") { - return ( -
- {element.name} - {element.name} -
- ); - } - - if (element.type === "audio") { - const audioBuffer = - element.sourceType === "library" ? element.buffer : undefined; - - const audioUrl = - element.sourceType === "library" - ? element.sourceUrl - : mediaAssets.find((asset) => asset.id === element.mediaId)?.url; - - if (audioBuffer || audioUrl) { - return ( -
-
- -
-
- ); - } - - return ( - - {element.name} - - ); - } - - const mediaAsset = mediaAssets.find((asset) => asset.id === element.mediaId); - if (!mediaAsset) { - return ( - - {element.name} - - ); - } - - if ( - mediaAsset.type === "image" || - (mediaAsset.type === "video" && mediaAsset.thumbnailUrl) - ) { - const trackHeight = getTrackHeight({ type: track.type }); - const tileWidth = trackHeight * (16 / 9); - const imageUrl = - mediaAsset.type === "image" ? mediaAsset.url : mediaAsset.thumbnailUrl; - - return ( -
-
-
-
-
- ); - } - - return ( - {element.name} - ); -} - -function CopyMenuItem() { - return ( - }> - Copy - - ); -} - -function MuteMenuItem({ - isMultipleSelected, - isCurrentElementSelected, - isMuted, -}: { - isMultipleSelected: boolean; - isCurrentElementSelected: boolean; - isMuted: boolean; -}) { - const getIcon = () => { - if (isMultipleSelected && isCurrentElementSelected) { - return ; - } - return isMuted ? ( - - ) : ( - - ); - }; - - return ( - - {isMuted ? "Unmute" : "Mute"} - - ); -} - -function VisibilityMenuItem({ - element, - isMultipleSelected, - isCurrentElementSelected, -}: { - element: TimelineElementType; - isMultipleSelected: boolean; - isCurrentElementSelected: boolean; -}) { - const isHidden = canElementBeHidden(element) && element.hidden; - - const getIcon = () => { - if (isMultipleSelected && isCurrentElementSelected) { - return ; - } - return isHidden ? ( - - ) : ( - - ); - }; - - return ( - - {isHidden ? "Show" : "Hide"} - - ); -} - -function DeleteMenuItem({ - isMultipleSelected, - isCurrentElementSelected, - elementType, - selectedCount, -}: { - isMultipleSelected: boolean; - isCurrentElementSelected: boolean; - elementType: TimelineElementType["type"]; - selectedCount: number; -}) { - return ( - } - > - {isMultipleSelected && isCurrentElementSelected - ? `Delete ${selectedCount} elements` - : `Delete ${elementType === "text" ? "text" : "clip"}`} - - ); -} - -function ActionMenuItem({ - action, - children, - ...props -}: Omit, "onClick" | "textRight"> & { - action: TAction; -}) { - return ( - { - event.stopPropagation(); - invokeAction(action); - }} - textRight={getDisplayShortcut(action)} - {...props} - > - {children} - - ); -} -- cgit v1.3.1