Merge pull request #244 from ateendra24/fix-issue-226

feat: add fullscreen video player
This commit is contained in:
Sid
2026-03-22 09:39:54 -07:00
committed by GitHub
5 changed files with 57 additions and 5 deletions
@@ -1,4 +1,4 @@
import { Pause, Play } from "lucide-react";
import { Maximize, Minimize, Pause, Play } from "lucide-react";
import { useScopedT } from "@/contexts/I18nContext";
import { cn } from "@/lib/utils";
import { Button } from "../ui/button";
@@ -7,6 +7,8 @@ interface PlaybackControlsProps {
isPlaying: boolean;
currentTime: number;
duration: number;
isFullscreen?: boolean;
onToggleFullscreen?: () => void;
onTogglePlayPause: () => void;
onSeek: (time: number) => void;
}
@@ -15,6 +17,8 @@ export default function PlaybackControls({
isPlaying,
currentTime,
duration,
isFullscreen = false,
onToggleFullscreen,
onTogglePlayPause,
onSeek,
}: PlaybackControlsProps) {
@@ -87,6 +91,21 @@ export default function PlaybackControls({
<span className="text-[9px] font-medium text-slate-500 tabular-nums w-[30px]">
{formatTime(duration)}
</span>
{onToggleFullscreen && (
<Button
onClick={onToggleFullscreen}
size="icon"
className="w-7 h-7 rounded-full transition-all duration-200 border border-transparent hover:bg-white/10 text-white hover:border-white/10 shrink-0 shadow-none ml-0.5"
aria-label={isFullscreen ? t("playback.exitFullscreen") : t("playback.fullscreen")}
>
{isFullscreen ? (
<Minimize className="w-3.5 h-3.5" />
) : (
<Maximize className="w-3.5 h-3.5" />
)}
</Button>
)}
</div>
);
}
+28 -1
View File
@@ -119,8 +119,11 @@ export default function VideoEditor() {
fileName: string;
format: string;
} | null>(null);
const [isFullscreen, setIsFullscreen] = useState(false);
const playerContainerRef = useRef<HTMLDivElement>(null);
const videoPlaybackRef = useRef<VideoPlaybackRef>(null);
const nextZoomIdRef = useRef(1);
const nextTrimIdRef = useRef(1);
const nextSpeedIdRef = useRef(1);
@@ -539,6 +542,21 @@ export default function VideoEditor() {
}
}
const toggleFullscreen = useCallback(() => {
setIsFullscreen((prev) => !prev);
}, []);
useEffect(() => {
if (!isFullscreen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") {
setIsFullscreen(false);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [isFullscreen]);
function handleSeek(time: number) {
const video = videoPlaybackRef.current?.video;
if (!video) return;
@@ -1425,7 +1443,14 @@ export default function VideoEditor() {
<PanelGroup direction="vertical" className="gap-3">
{/* Top section: video preview and controls */}
<Panel defaultSize={70} maxSize={70} minSize={40}>
<div className="w-full h-full flex flex-col items-center justify-center bg-black/40 rounded-2xl border border-white/5 shadow-2xl overflow-hidden">
<div
ref={playerContainerRef}
className={
isFullscreen
? "fixed inset-0 z-[99999] w-full h-full flex flex-col items-center justify-center bg-[#09090b]"
: "w-full h-full flex flex-col items-center justify-center bg-black/40 rounded-2xl border border-white/5 shadow-2xl overflow-hidden relative"
}
>
{/* Video preview */}
<div className="w-full flex justify-center items-center flex-auto mt-1.5">
<div
@@ -1487,6 +1512,8 @@ export default function VideoEditor() {
isPlaying={isPlaying}
currentTime={currentTime}
duration={duration}
isFullscreen={isFullscreen}
onToggleFullscreen={toggleFullscreen}
onTogglePlayPause={togglePlayPause}
onSeek={handleSeek}
/>
+3 -1
View File
@@ -18,7 +18,9 @@
},
"playback": {
"play": "Play",
"pause": "Pause"
"pause": "Pause",
"fullscreen": "Fullscreen",
"exitFullscreen": "Exit Fullscreen"
},
"locale": {
"name": "English",
+3 -1
View File
@@ -18,7 +18,9 @@
},
"playback": {
"play": "Reproducir",
"pause": "Pausar"
"pause": "Pausar",
"fullscreen": "Pantalla completa",
"exitFullscreen": "Salir de pantalla completa"
},
"locale": {
"name": "Español",
+3 -1
View File
@@ -18,7 +18,9 @@
},
"playback": {
"play": "播放",
"pause": "暂停"
"pause": "暂停",
"fullscreen": "全屏",
"exitFullscreen": "退出全屏"
},
"locale": {
"name": "中文",