| import React from 'react'; |
|
|
| export interface SubtitleSegment { |
| id: number; |
| startTime: string; |
| endTime: string; |
| duration: string; |
| sourceText: string; |
| targetText?: string; |
| isCurrent?: boolean; |
| } |
|
|
| export interface VideoInfo { |
| title: string; |
| duration: string; |
| totalSegments: number; |
| currentSegment: number; |
| } |
|
|
| interface SubtitlingModuleProps { |
| videoInfo: VideoInfo; |
| subtitleSegments: SubtitleSegment[]; |
| currentDisplayedSubtitle?: string; |
| onSegmentClick?: (id: number) => void; |
| getSegmentButtonClass?: (id: number) => string; |
| onPlayPause?: () => void; |
| isPlaying?: boolean; |
| onSaveSegment?: (id: number, text: string) => void; |
| } |
|
|
| |
| |
| |
| |
| const SubtitlingModule: React.FC<SubtitlingModuleProps> = ({ |
| videoInfo, |
| subtitleSegments, |
| currentDisplayedSubtitle, |
| onSegmentClick, |
| getSegmentButtonClass, |
| onPlayPause, |
| isPlaying, |
| }) => { |
| return ( |
| <div className="grid grid-cols-1 lg:grid-cols-2 gap-8"> |
| <div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6"> |
| <div className="mb-4"> |
| <h3 className="text-xl font-bold text-gray-900 mb-2">{videoInfo.title}</h3> |
| </div> |
| <div className="bg-black rounded-lg aspect-video overflow-hidden relative"> |
| <div className="absolute inset-0 flex items-center justify-center text-white/70 text-sm">Video Placeholder</div> |
| {currentDisplayedSubtitle && ( |
| <div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-10"> |
| <div className="bg-black bg-opacity-80 text-white px-6 py-3 rounded-lg text-center max-w-lg"> |
| <p className={`text-base font-medium leading-relaxed tracking-wide ${currentDisplayedSubtitle.length <= 42 ? 'whitespace-nowrap' : 'whitespace-pre-line'}`}> |
| {currentDisplayedSubtitle} |
| </p> |
| </div> |
| </div> |
| )} |
| </div> |
| </div> |
| |
| <div className="bg-white rounded-xl shadow-lg border border-gray-100 p-6"> |
| <h3 className="text-xl font-bold text-gray-900 mb-4">Translation Workspace</h3> |
| <div className="grid grid-cols-9 gap-1 mb-6"> |
| {subtitleSegments.map((segment) => ( |
| <button |
| key={segment.id} |
| onClick={() => onSegmentClick && onSegmentClick(segment.id)} |
| className={`px-1 py-1 rounded text-xs w-full ${getSegmentButtonClass ? getSegmentButtonClass(segment.id) : ''}`} |
| > |
| {segment.id} |
| </button> |
| ))} |
| </div> |
| <div className="flex items-center gap-2 mb-4"> |
| <button onClick={onPlayPause} className="px-3 py-1.5 text-sm rounded-md border border-gray-300"> |
| {isPlaying ? 'Pause' : 'Play'} |
| </button> |
| <div className="text-sm text-gray-600">{videoInfo.currentSegment}/{videoInfo.totalSegments}</div> |
| </div> |
| <div className="space-y-4"> |
| {subtitleSegments.map(seg => ( |
| <div key={seg.id} className="border border-gray-200 rounded-lg p-3"> |
| <div className="text-xs text-gray-500 mb-1">{seg.startTime} → {seg.endTime} ({seg.duration})</div> |
| <div className="text-sm text-gray-800 mb-2">{seg.sourceText}</div> |
| <textarea className="w-full border border-gray-300 rounded p-2 text-sm" defaultValue={seg.targetText || ''} rows={2} /> |
| </div> |
| ))} |
| </div> |
| </div> |
| </div> |
| ); |
| }; |
|
|
| export default SubtitlingModule; |
|
|
|
|
|
|