[dyad] Add video trimming controls - wrote 1 file(s)
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useRef, ChangeEvent } from "react";
|
import { useState, useRef, ChangeEvent, SyntheticEvent } from "react";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { Slider } from "@/components/ui/slider";
|
||||||
import { UploadCloud, Scissors, Download } from "lucide-react";
|
import { UploadCloud, Scissors, Download } from "lucide-react";
|
||||||
|
|
||||||
export function VideoEditor() {
|
export function VideoEditor() {
|
||||||
const [videoSrc, setVideoSrc] = useState<string | null>(null);
|
const [videoSrc, setVideoSrc] = useState<string | null>(null);
|
||||||
const [videoFile, setVideoFile] = useState<File | null>(null);
|
const [videoFile, setVideoFile] = useState<File | null>(null);
|
||||||
|
const [duration, setDuration] = useState(0);
|
||||||
|
const [trimValues, setTrimValues] = useState([0, 0]);
|
||||||
const videoRef = useRef<HTMLVideoElement>(null);
|
const videoRef = useRef<HTMLVideoElement>(null);
|
||||||
|
|
||||||
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
@@ -21,6 +24,24 @@ export function VideoEditor() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleLoadedMetadata = (e: SyntheticEvent<HTMLVideoElement>) => {
|
||||||
|
const video = e.currentTarget;
|
||||||
|
setDuration(video.duration);
|
||||||
|
setTrimValues([0, video.duration]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatTime = (timeInSeconds: number) => {
|
||||||
|
if (isNaN(timeInSeconds) || timeInSeconds < 0) {
|
||||||
|
return "00:00.000";
|
||||||
|
}
|
||||||
|
const minutes = Math.floor(timeInSeconds / 60);
|
||||||
|
const seconds = Math.floor(timeInSeconds % 60);
|
||||||
|
const milliseconds = Math.floor((timeInSeconds % 1) * 1000);
|
||||||
|
return `${String(minutes).padStart(2, "0")}:${String(
|
||||||
|
seconds
|
||||||
|
).padStart(2, "0")}.${String(milliseconds).padStart(3, "0")}`;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="w-full shadow-lg rounded-2xl border-0">
|
<Card className="w-full shadow-lg rounded-2xl border-0">
|
||||||
<CardHeader className="text-center">
|
<CardHeader className="text-center">
|
||||||
@@ -40,13 +61,24 @@ export function VideoEditor() {
|
|||||||
src={videoSrc}
|
src={videoSrc}
|
||||||
controls
|
controls
|
||||||
className="w-full h-full object-contain bg-black"
|
className="w-full h-full object-contain bg-black"
|
||||||
|
onLoadedMetadata={handleLoadedMetadata}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold mb-2">Trim Video</h3>
|
<h3 className="text-lg font-semibold mb-4">Trim Video</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<div className="space-y-4">
|
||||||
Trimming controls will be added here in the next step.
|
<Slider
|
||||||
</p>
|
value={trimValues}
|
||||||
|
onValueChange={setTrimValues}
|
||||||
|
max={duration}
|
||||||
|
step={0.1}
|
||||||
|
aria-label="Video trimmer"
|
||||||
|
/>
|
||||||
|
<div className="flex justify-between text-sm font-mono text-muted-foreground">
|
||||||
|
<span>Start: {formatTime(trimValues[0])}</span>
|
||||||
|
<span>End: {formatTime(trimValues[1])}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user