diff options
| author | Zaid-maker <53424436+Zaid-maker@users.noreply.github.com> | 2025-06-24 16:59:44 +0500 |
|---|---|---|
| committer | Zaid-maker <53424436+Zaid-maker@users.noreply.github.com> | 2025-06-24 16:59:44 +0500 |
| commit | 62051de6c11dde40e2929c030e4418f87b137e42 (patch) | |
| tree | 3492ed2abd6a127512a6ce09543bcf770bcd53d5 /apps/web/src/components/ui | |
| parent | 7c83b8e70b2024d79f053bd40e6f633969c2c1f5 (diff) | |
| parent | 900deab065ef17941262f48524af786cac302945 (diff) | |
| download | opencut-62051de6c11dde40e2929c030e4418f87b137e42.tar.gz | |
Merge branch 'main' into implement-workflows
Diffstat (limited to 'apps/web/src/components/ui')
| -rw-r--r-- | apps/web/src/components/ui/button.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/calendar.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/command.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/input.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/pagination.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/sidebar.tsx | 2 | ||||
| -rw-r--r-- | apps/web/src/components/ui/video-player.tsx | 96 |
7 files changed, 41 insertions, 67 deletions
diff --git a/apps/web/src/components/ui/button.tsx b/apps/web/src/components/ui/button.tsx index f5863e20..d4406d5b 100644 --- a/apps/web/src/components/ui/button.tsx +++ b/apps/web/src/components/ui/button.tsx @@ -17,7 +17,7 @@ const buttonVariants = cva( "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", + text: "bg-transparent p-0 rounded-none hover:text-muted-foreground", // Instead of ghost (matches app better) link: "text-primary underline-offset-4 hover:underline", }, size: { diff --git a/apps/web/src/components/ui/calendar.tsx b/apps/web/src/components/ui/calendar.tsx index 2dca9b14..192643cb 100644 --- a/apps/web/src/components/ui/calendar.tsx +++ b/apps/web/src/components/ui/calendar.tsx @@ -43,7 +43,7 @@ function Calendar({ : "[&:has([aria-selected])]:rounded-md" ), day: cn( - buttonVariants({ variant: "ghost" }), + buttonVariants({ variant: "text" }), "h-8 w-8 p-0 font-normal aria-selected:opacity-100" ), day_range_start: "day-range-start", diff --git a/apps/web/src/components/ui/command.tsx b/apps/web/src/components/ui/command.tsx index 29f29cf2..11b27041 100644 --- a/apps/web/src/components/ui/command.tsx +++ b/apps/web/src/components/ui/command.tsx @@ -1,7 +1,7 @@ "use client"; import * as React from "react"; -import { type DialogProps } from "radix-ui"; +import { DialogProps } from "@radix-ui/react-dialog"; import { Command as CommandPrimitive } from "cmdk"; import { Search } from "lucide-react"; diff --git a/apps/web/src/components/ui/input.tsx b/apps/web/src/components/ui/input.tsx index 42f4c452..72314045 100644 --- a/apps/web/src/components/ui/input.tsx +++ b/apps/web/src/components/ui/input.tsx @@ -41,7 +41,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>( {showPasswordToggle && ( <Button type="button" - variant="ghost" + variant="text" size="icon" onClick={() => onShowPasswordChange?.(!showPassword)} className="absolute right-0 top-0 h-full px-3 text-muted-foreground hover:text-foreground" diff --git a/apps/web/src/components/ui/pagination.tsx b/apps/web/src/components/ui/pagination.tsx index 79fd268e..61766cec 100644 --- a/apps/web/src/components/ui/pagination.tsx +++ b/apps/web/src/components/ui/pagination.tsx @@ -49,7 +49,7 @@ const PaginationLink = ({ aria-current={isActive ? "page" : undefined} className={cn( buttonVariants({ - variant: isActive ? "outline" : "ghost", + variant: isActive ? "outline" : "text", size, }), className diff --git a/apps/web/src/components/ui/sidebar.tsx b/apps/web/src/components/ui/sidebar.tsx index e69d8751..c1583503 100644 --- a/apps/web/src/components/ui/sidebar.tsx +++ b/apps/web/src/components/ui/sidebar.tsx @@ -269,7 +269,7 @@ const SidebarTrigger = React.forwardRef< <Button ref={ref} data-sidebar="trigger" - variant="ghost" + variant="text" size="icon" className={cn("h-8 w-8", className)} onClick={(event) => { diff --git a/apps/web/src/components/ui/video-player.tsx b/apps/web/src/components/ui/video-player.tsx index 0c4f8498..32a12916 100644 --- a/apps/web/src/components/ui/video-player.tsx +++ b/apps/web/src/components/ui/video-player.tsx @@ -1,8 +1,6 @@ "use client"; import { useRef, useEffect } from "react"; -import { Button } from "./button"; -import { Play, Pause, Volume2 } from "lucide-react"; import { usePlaybackStore } from "@/stores/playback-store"; interface VideoPlayerProps { @@ -25,113 +23,89 @@ export function VideoPlayer({ clipDuration }: VideoPlayerProps) { const videoRef = useRef<HTMLVideoElement>(null); - const { isPlaying, currentTime, volume, play, pause, setVolume } = usePlaybackStore(); + const { isPlaying, currentTime, volume, speed } = usePlaybackStore(); // Calculate if we're within this clip's timeline range const clipEndTime = clipStartTime + (clipDuration - trimStart - trimEnd); const isInClipRange = currentTime >= clipStartTime && currentTime < clipEndTime; - // Calculate the video's internal time based on timeline position - const videoTime = Math.max(trimStart, Math.min( - clipDuration - trimEnd, - currentTime - clipStartTime + trimStart - )); - + // Sync playback events useEffect(() => { const video = videoRef.current; - if (!video) return; + if (!video || !isInClipRange) return; const handleSeekEvent = (e: CustomEvent) => { - if (!isInClipRange) return; + // Always update video time, even if outside clip range const timelineTime = e.detail.time; - const newVideoTime = Math.max(trimStart, Math.min( + const videoTime = Math.max(trimStart, Math.min( clipDuration - trimEnd, timelineTime - clipStartTime + trimStart )); - video.currentTime = newVideoTime; + video.currentTime = videoTime; }; const handleUpdateEvent = (e: CustomEvent) => { - if (!isInClipRange) return; + // Always update video time, even if outside clip range const timelineTime = e.detail.time; - const targetVideoTime = Math.max(trimStart, Math.min( + const targetTime = Math.max(trimStart, Math.min( clipDuration - trimEnd, timelineTime - clipStartTime + trimStart )); - // Only sync if there's a significant difference - if (Math.abs(video.currentTime - targetVideoTime) > 0.2) { - video.currentTime = targetVideoTime; + if (Math.abs(video.currentTime - targetTime) > 0.5) { + video.currentTime = targetTime; } }; + const handleSpeed = (e: CustomEvent) => { + video.playbackRate = e.detail.speed; + }; + window.addEventListener("playback-seek", handleSeekEvent as EventListener); window.addEventListener("playback-update", handleUpdateEvent as EventListener); + window.addEventListener("playback-speed", handleSpeed as EventListener); return () => { window.removeEventListener("playback-seek", handleSeekEvent as EventListener); window.removeEventListener("playback-update", handleUpdateEvent as EventListener); + window.removeEventListener("playback-speed", handleSpeed as EventListener); }; }, [clipStartTime, trimStart, trimEnd, clipDuration, isInClipRange]); - // Sync video playback state - only play if in clip range + // Sync playback state useEffect(() => { const video = videoRef.current; if (!video) return; if (isPlaying && isInClipRange) { - video.play().catch(console.error); + video.play().catch(() => { }); } else { video.pause(); } }, [isPlaying, isInClipRange]); - // Sync volume + // Sync volume and speed useEffect(() => { const video = videoRef.current; if (!video) return; + video.volume = volume; - }, [volume]); + video.playbackRate = speed; + }, [volume, speed]); return ( - <div className={`relative group ${className}`}> - <video - ref={videoRef} - src={src} - poster={poster} - className="w-full h-full object-cover" - playsInline - preload="metadata" - /> - - <div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" /> - - <div className="absolute bottom-2 left-2 right-2 flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity"> - <Button - variant="ghost" - size="icon" - className="h-8 w-8 bg-black/50 text-white hover:bg-black/70" - onClick={isPlaying ? pause : play} - > - {isPlaying ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />} - </Button> - - <div className="flex-1 h-1 bg-white/30 rounded-full overflow-hidden"> - <div - className="h-full bg-white transition-all duration-100" - style={{ width: `${(currentTime / usePlaybackStore.getState().duration) * 100}%` }} - /> - </div> - - <Button - variant="ghost" - size="icon" - className="h-8 w-8 bg-black/50 text-white hover:bg-black/70" - onClick={() => setVolume(volume > 0 ? 0 : 1)} - > - <Volume2 className="h-4 w-4" /> - </Button> - </div> - </div> + <video + ref={videoRef} + src={src} + poster={poster} + className={`w-full h-full object-cover ${className}`} + playsInline + preload="auto" + controls={false} + disablePictureInPicture + disableRemotePlayback + style={{ pointerEvents: 'none' }} + onContextMenu={(e) => e.preventDefault()} + /> ); }
\ No newline at end of file |
