diff options
| author | Hyteq <DerpsDer.es@gmail.com> | 2025-06-23 09:35:32 +0300 |
|---|---|---|
| committer | Hyteq <DerpsDer.es@gmail.com> | 2025-06-23 09:35:32 +0300 |
| commit | f688c7ef5d8b4b97a74162d97508092901311379 (patch) | |
| tree | 1fd2641f8a549370b2ac2fc0a12348d5bd121820 /apps/web/src/components/editor | |
| parent | 68864c144221d1cff996c9d7a2499e7b7e741086 (diff) | |
| download | opencut-f688c7ef5d8b4b97a74162d97508092901311379.tar.gz | |
fix: video player properly reflecting the edited timeline, video start
Diffstat (limited to 'apps/web/src/components/editor')
| -rw-r--r-- | apps/web/src/components/editor/preview-panel.tsx | 54 | ||||
| -rw-r--r-- | apps/web/src/components/editor/timeline.tsx | 25 |
2 files changed, 44 insertions, 35 deletions
diff --git a/apps/web/src/components/editor/preview-panel.tsx b/apps/web/src/components/editor/preview-panel.tsx index 593758e1..74bf5f98 100644 --- a/apps/web/src/components/editor/preview-panel.tsx +++ b/apps/web/src/components/editor/preview-panel.tsx @@ -11,39 +11,59 @@ import { Play, Pause } from "lucide-react"; export function PreviewPanel() {
const { tracks } = useTimelineStore();
const { mediaItems } = useMediaStore();
- const { isPlaying, toggle } = usePlaybackStore();
+ const { isPlaying, toggle, currentTime } = usePlaybackStore();
- const firstClip = tracks[0]?.clips[0];
- const firstMediaItem = firstClip
- ? mediaItems.find((item) => item.id === firstClip.mediaId)
+ // Find the active clip at the current playback time
+ const getActiveClip = () => {
+ for (const track of tracks) {
+ for (const clip of track.clips) {
+ const clipStart = clip.startTime;
+ const clipEnd = clip.startTime + (clip.duration - clip.trimStart - clip.trimEnd);
+
+ if (currentTime >= clipStart && currentTime < clipEnd) {
+ return clip;
+ }
+ }
+ }
+ return null;
+ };
+
+ const activeClip = getActiveClip();
+ const activeMediaItem = activeClip
+ ? mediaItems.find((item) => item.id === activeClip.mediaId)
: null;
- const aspectRatio = firstMediaItem?.aspectRatio || 16 / 9;
+ const aspectRatio = activeMediaItem?.aspectRatio || 16 / 9;
const renderContent = () => {
- if (!firstMediaItem) {
+ if (!activeMediaItem || !activeClip) {
return (
<div className="absolute inset-0 flex items-center justify-center text-muted-foreground/50">
- Drop media to start editing
+ {tracks.length === 0 ? "Drop media to start editing" : "No clip at current time"}
</div>
);
}
- if (firstMediaItem.type === "video") {
+ // Calculate the relative time within the clip (accounting for trim)
+ const relativeTime = Math.max(0, currentTime - activeClip.startTime + activeClip.trimStart);
+
+ if (activeMediaItem.type === "video") {
return (
<VideoPlayer
- src={firstMediaItem.url}
- poster={firstMediaItem.thumbnailUrl}
+ src={activeMediaItem.url}
+ poster={activeMediaItem.thumbnailUrl}
className="w-full h-full"
+ startTime={relativeTime}
+ key={`${activeClip.id}-${activeClip.trimStart}-${activeClip.trimEnd}`}
/>
);
}
- if (firstMediaItem.type === "image") {
+ if (activeMediaItem.type === "image") {
return (
<ImageTimelineTreatment
- src={firstMediaItem.url}
- alt={firstMediaItem.name}
+ src={activeMediaItem.url}
+ alt={activeMediaItem.name}
targetAspectRatio={aspectRatio}
className="w-full h-full"
backgroundType="blur"
@@ -51,12 +71,12 @@ export function PreviewPanel() { );
}
- if (firstMediaItem.type === "audio") {
+ if (activeMediaItem.type === "audio") {
return (
<div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-green-500/20 to-emerald-500/20">
<div className="text-center">
<div className="text-6xl mb-4">🎵</div>
- <p className="text-muted-foreground">{firstMediaItem.name}</p>
+ <p className="text-muted-foreground">{activeMediaItem.name}</p>
<Button
variant="outline"
className="mt-4"
@@ -88,10 +108,10 @@ export function PreviewPanel() { {renderContent()}
</div>
- {firstMediaItem && (
+ {activeMediaItem && (
<div className="mt-4 text-center">
<p className="text-sm text-muted-foreground">
- {firstMediaItem.name}
+ {activeMediaItem.name}
</p>
<p className="text-xs text-muted-foreground/70">
{aspectRatio.toFixed(2)} • {aspectRatio > 1 ? "Landscape" : aspectRatio < 1 ? "Portrait" : "Square"}
diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index ed9128dc..be532991 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -259,19 +259,6 @@ export function Timeline() { >
{/* Timeline Header */}
<div className="py-3 relative bg-muted/30 border-b">
- {/* Playhead */}
- {duration > 0 && (
- <div
- className="absolute top-0 bottom-0 w-0.5 bg-red-500 pointer-events-none z-10"
- style={{
- left: `${(currentTime / (duration / zoomLevel)) * 100}%`,
- transform: 'translateX(-50%)'
- }}
- >
- <div className="absolute -top-1 left-1/2 transform -translate-x-1/2 w-3 h-3 bg-red-500 rounded-full border-2 border-white shadow-sm" />
- </div>
- )}
-
{/* Zoom indicator */}
<div className="absolute top-1 right-2 text-xs text-muted-foreground">
{zoomLevel.toFixed(1)}x
@@ -301,14 +288,15 @@ export function Timeline() { )}
{/* Playhead for tracks area */}
- {tracks.length > 0 && duration > 0 && (
+ {tracks.length > 0 && (
<div
- className="absolute top-0 bottom-0 w-0.5 bg-red-500/80 pointer-events-none z-10"
+ className="absolute top-0 bottom-0 w-0.5 bg-red-500 pointer-events-none z-20"
style={{
- left: `${(currentTime / (duration / zoomLevel)) * 100}%`,
- transform: 'translateX(-50%)'
+ left: `${currentTime * 50 * zoomLevel + 128}px`,
}}
- />
+ >
+ <div className="absolute -top-8 left-1/2 transform -translate-x-1/2 w-3 h-3 bg-red-500 rounded-full border-2 border-white shadow-sm" />
+ </div>
)}
</div>
</div>
@@ -321,6 +309,7 @@ function TimelineTrackComponent({ track, zoomLevel }: { track: TimelineTrack, zo const { mediaItems } = useMediaStore();
const { moveClipToTrack, updateClipTrim, updateClipStartTime } = useTimelineStore();
const [isDropping, setIsDropping] = useState(false);
+ const [dropPosition, setDropPosition] = useState<number | null>(null);
const [resizing, setResizing] = useState<{
clipId: string;
side: 'left' | 'right';
|
