omniasr-transcriptions / frontend /src /pages /TranscriptionPage.tsx
jeanma's picture
Omnilingual ASR transcription demo
ae238b3 verified
import React from "react";
import {useState, useRef, useCallback} from "react";
import {useTranscriptionStore} from "../stores/transcriptionStore";
import {
SUPPORTED_AUDIO_FORMATS,
SUPPORTED_VIDEO_FORMATS,
CODEC_INFO,
} from "../utils/mediaTypes";
import TranscriptionSideBar from "../components/TranscriptionSideBar";
import TranscriptionPlayer from "../components/TranscriptionPlayer";
import MediaRecorder from "../components/MediaRecorder";
import {useDragAndDrop} from "../hooks/useDragAndDrop";
import {CloudArrowUpIcon} from "@heroicons/react/24/outline";
import ErrorBoundary from "../components/ErrorBoundary";
export default function TranscriptionPage() {
const {isRecording, setFile, stopRecording} = useTranscriptionStore();
// Sidebar resizing state
const [sidebarWidth, setSidebarWidth] = useState(256); // Default 256px (w-64)
const [isResizing, setIsResizing] = useState(false);
const sidebarRef = useRef<HTMLDivElement>(null);
// Drag and drop functionality
const {isDragActive, dragProps} = useDragAndDrop({
onFileDropped: setFile,
acceptedTypes: ["audio/*"],
});
// Handle sidebar resizing
const handleMouseDown = useCallback((e: React.MouseEvent) => {
e.preventDefault();
setIsResizing(true);
}, []);
const handleMouseMove = useCallback(
(e: MouseEvent) => {
if (!isResizing) return;
const newWidth = Math.max(200, Math.min(600, e.clientX)); // Min 200px, max 600px
setSidebarWidth(newWidth);
},
[isResizing]
);
const handleMouseUp = useCallback(() => {
setIsResizing(false);
}, []);
// Add global mouse event listeners
React.useEffect(() => {
if (isResizing) {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
document.body.style.userSelect = "none"; // Prevent text selection during drag
document.body.style.cursor = "ew-resize";
}
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
document.body.style.userSelect = "";
document.body.style.cursor = "";
};
}, [isResizing, handleMouseMove, handleMouseUp]);
return (
<ErrorBoundary componentName="TranscriptionPage">
<div className="flex h-screen bg-gray-900 relative" {...dragProps}>
{/* Drag Overlay */}
{isDragActive && (
<div className="absolute inset-0 bg-blue-900/80 border-4 border-dashed border-blue-400 z-50 flex items-center justify-center">
<div className="text-center text-white">
<CloudArrowUpIcon className="w-16 h-16 mx-auto mb-4 text-blue-300" />
<div className="text-2xl font-semibold mb-2">
Drop your audio file here
</div>
<div className="text-lg text-blue-200 mb-4">
Supports audio files only
</div>
{/* Audio formats section */}
<div className="text-center mb-3">
<div className="text-sm font-medium text-blue-300 mb-1">
Audio Formats
</div>
<div className="text-xs text-blue-100 opacity-90">
{SUPPORTED_AUDIO_FORMATS.join(" • ")}
</div>
</div>
{/* Codec info */}
<div className="text-center">
<div className="text-xs text-blue-200 opacity-75">
Best with standard codecs:{" "}
{CODEC_INFO.audio.common.slice(0, 2).join(", ")}
</div>
</div>
</div>
</div>
)}
{/* Sidebar with Resize Handle */}
<div className="relative flex">
<div
ref={sidebarRef}
className="flex-shrink-0 bg-gray-800 text-white overflow-y-auto"
style={{width: `${sidebarWidth}px`}}
>
<TranscriptionSideBar />
</div>
{/* Drag Handle */}
<div
className="w-1 bg-gray-600 hover:bg-gray-500 cursor-ew-resize flex-shrink-0 transition-colors duration-150"
onMouseDown={handleMouseDown}
title="Drag to resize sidebar"
/>
</div>
{/* Main Content */}
<ErrorBoundary componentName="TranscriptionPlayer">
{isRecording ? (
<div className="flex-1 flex items-center justify-center bg-gray-900">
<MediaRecorder
onComplete={() => stopRecording()}
onCancel={() => stopRecording()}
/>
</div>
) : (
<TranscriptionPlayer />
)}
</ErrorBoundary>
</div>
</ErrorBoundary>
);
}