11import { useState , useRef , useEffect } from 'react' ;
2- import type { RecordedSession , TimelineSegment } from '../types' ;
2+ import type { RecordedSession , TimelineSegment , AudioClip } from '../types' ;
33import { formatTime } from '../utils/timeUtils' ;
44
55interface VideoTimelineProps {
@@ -18,6 +18,11 @@ interface VideoTimelineProps {
1818 trimStart ?: number ;
1919 trimEnd ?: number ;
2020 onTrimChange ?: ( start : number , end : number ) => void ;
21+
22+ // Audio Clips
23+ audioClips ?: AudioClip [ ] ;
24+ onAudioClipUpdate ?: ( id : string , updates : Partial < AudioClip > ) => void ;
25+ onAudioClipSelect ?: ( id : string ) => void ;
2126}
2227
2328export const VideoTimeline = ( {
@@ -28,10 +33,12 @@ export const VideoTimeline = ({
2833 onSegmentSelect,
2934 playbackTime,
3035 onSeek,
31- trimMode = false ,
3236 trimStart : externalTrimStart ,
3337 trimEnd : externalTrimEnd ,
34- onTrimChange
38+ onTrimChange,
39+ audioClips = [ ] ,
40+ onAudioClipUpdate,
41+ onAudioClipSelect
3542} : VideoTimelineProps ) => {
3643 const timelineRef = useRef < HTMLDivElement > ( null ) ;
3744 const containerRef = useRef < HTMLDivElement > ( null ) ;
@@ -48,7 +55,15 @@ export const VideoTimeline = ({
4855 // Optimized Dragging State
4956 const [ draggingSegmentId , setDraggingSegmentId ] = useState < string | null > ( null ) ;
5057 const [ dragNewStartTime , setDragNewStartTime ] = useState < number > ( 0 ) ;
51- const dragNewStartTimeRef = useRef < number > ( 0 ) ; // Ref to track latest value for closure access
58+ const dragNewStartTimeRef = useRef < number > ( 0 ) ;
59+
60+ // Audio Dragging Logic
61+ const [ draggingAudioId , setDraggingAudioId ] = useState < string | null > ( null ) ;
62+ const [ draggingAudioType , setDraggingAudioType ] = useState < 'move' | 'start' | 'end' | null > ( null ) ;
63+ const [ dragAudioNewStart , setDragAudioNewStart ] = useState < number > ( 0 ) ;
64+ const [ dragAudioNewDuration , setDragAudioNewDuration ] = useState < number > ( 0 ) ;
65+ const [ dragAudioNewSourceStart , setDragAudioNewSourceStart ] = useState < number > ( 0 ) ;
66+ const dragAudioStateRef = useRef ( { start : 0 , duration : 0 , sourceStart : 0 } ) ;
5267
5368 // Internal trim state (defaults to full duration)
5469 const duration = session ?. metadata . duration || 1000 ;
@@ -295,7 +310,7 @@ export const VideoTimeline = ({
295310 { /* Timeline Track Container */ }
296311 < div
297312 ref = { containerRef }
298- className = "relative h-24 bg-black/40 rounded-lg border border-white/10 overflow-x-auto overflow-y-hidden cursor-pointer select-none"
313+ className = "relative h-auto min-h-[6rem] bg-black/40 rounded-lg border border-white/10 overflow-x-auto overflow-y-hidden cursor-pointer select-none py-2 px-4 space-y-2 "
299314 onMouseDown = { handleTimelineMouseDown }
300315 onMouseMove = { handleMouseMove }
301316 onMouseUp = { handleMouseUp }
@@ -528,6 +543,53 @@ export const VideoTimeline = ({
528543 </ div >
529544 </ div >
530545
546+ { /* Audio Track Container */ }
547+ { audioClips . length > 0 && (
548+ < div
549+ className = "relative h-12 bg-neutral-900/40 rounded-lg border border-white/5 overflow-hidden mt-1"
550+ style = { { width : '100%' } }
551+ >
552+ < div
553+ className = "absolute top-0 bottom-0"
554+ style = { {
555+ left : - scrollLeft , // Match scrolling of video track? Or separate?
556+ // Currently timeline container handles scroll. This track needs to sync.
557+ // Actually, separate container implies separate scroll if not careful.
558+ // Better: Put this inside the same scrollable container?
559+ // No, structure is: Toolbar -> Video Track (scrollable) -> Time Markers
560+ // We should probably move the audio track inside the scrollable area or sync scroll.
561+ // Given existing structure, let's put it BELOW the time markers but synchronized?
562+ // Simpler: Put it INSIDE the scrollable `containerRef` div, below the video track.
563+ width : `${ zoomLevel * 100 } %`
564+ } }
565+ >
566+ { /* We can't put it inside containerRef because that one has fixed height h-24.
567+ We should refactor the layout to have a common scroll parent.
568+ For now, let's assume we render it separately and user has to scroll main track?
569+ Or we sync scroll.
570+ */ }
571+ </ div >
572+ </ div >
573+ ) }
574+
575+ { /*
576+ Refactor: To support multi-track scrolling, we need a common scroll container.
577+ Let's change the structure quickly.
578+ Outer: Toolbar
579+ ScrollContainer (overflow-x)
580+ - TimeGrid (absolute)
581+ - VideoTrack (relative, h-24)
582+ - AudioTrack (relative, h-12, mt-1)
583+ */ }
584+
585+ { /* Re-implementing structure for multi-track support */ }
586+
587+ { /* ... Wait, editing the whole structure is risky with replace_file_content chunking.
588+ Let's try to inject the audio track INSIDE the existing containerRef div,
589+ and just increase the height of containerRef or allow it to grow?
590+ The container has `h-24` class. We should change that to `h-auto` or `min-h-[6rem]`.
591+ */ }
592+
531593 { /* Time Markers */ }
532594 < div className = "flex justify-between text-xs opacity-60 font-mono px-1" >
533595 < span > 00:00</ span >
0 commit comments