import { Clock, Download, Grid3X3, Heart, List, Play, Search, Share2, Star } from "lucide-react" import { FC, useMemo, useState } from "react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" import { Checkbox } from "@/components/ui/checkbox" import { Input } from "@/components/ui/input" import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs" import { cn } from "@/lib/utils" import type { KeyMoment, SceneAnalysis, UnifiedContentAnalysis } from "../../shared/types" interface PreviewItem { id: string type: "scene" | "moment" | "highlight" title: string description?: string thumbnailUrl: string timestamp: number duration: number score?: number tags: string[] isSelected?: boolean isStarred?: boolean } interface PreviewGridProps { analysis: UnifiedContentAnalysis | null className?: string viewMode?: "grid" | "list" itemsPerPage?: number enableSelection?: boolean enableFiltering?: boolean onItemSelect?: (item: PreviewItem) => void onItemPlay?: (item: PreviewItem) => void onItemDownload?: (item: PreviewItem) => void onItemStar?: (item: PreviewItem) => void onItemShare?: (item: PreviewItem) => void onSelectionChange?: (selectedItems: PreviewItem[]) => void } export const PreviewGrid: FC = ({ analysis, className, viewMode = "grid", itemsPerPage = 12, enableSelection = false, enableFiltering = true, onItemSelect, onItemPlay, onItemDownload, onItemStar, onItemShare, onSelectionChange, }) => { const [currentViewMode, setCurrentViewMode] = useState(viewMode) const [selectedItems, setSelectedItems] = useState>(new Set()) const [searchQuery, setSearchQuery] = useState("") const [filterType, setFilterType] = useState<"all" | "scene" | "moment" | "highlight">("all") const [sortBy, setSortBy] = useState<"timestamp" | "score" | "duration">("timestamp") const [currentPage, setCurrentPage] = useState(1) // Convert analysis data to preview items const previewItems = useMemo(() => { if (!analysis) return [] const items: PreviewItem[] = [] // Add scenes analysis.scenes.forEach((scene: SceneAnalysis) => { items.push({ id: `scene-${scene.id}`, type: "scene", title: `Сцена ${scene.type}`, description: `${scene.duration.toFixed(1)}с • ${scene.content.objects.length} объектов`, thumbnailUrl: scene.keyFrames[0]?.thumbnailPath || `/api/thumbnail?t=${scene.startTime}`, timestamp: scene.startTime, duration: scene.duration, score: scene.quality.overall, tags: [scene.type, `качество ${scene.quality.overall}%`], }) }) // Add key moments analysis.keyMoments.forEach((moment: KeyMoment) => { items.push({ id: `moment-${moment.id}`, type: "moment", title: moment.type.replace(/_/g, " "), description: moment.description, thumbnailUrl: `/api/thumbnail?t=${moment.timestamp}`, timestamp: moment.timestamp, duration: moment.duration, score: moment.score, tags: [moment.type, `оценка ${moment.score}`], }) }) // Add highlights from insights analysis.insights.highlights.forEach((highlight: string, index: number) => { items.push({ id: `highlight-${index}`, type: "highlight", title: "Основной момент", description: highlight, thumbnailUrl: `/api/thumbnail?t=${index * 30}`, // Distribute highlights timestamp: index * 30, duration: 5, score: 85 + Math.random() * 15, // Random high score for highlights tags: ["highlight", "важное"], }) }) return items }, [analysis]) // Filter and sort items const filteredItems = useMemo(() => { let filtered = previewItems // Apply type filter if (filterType !== "all") { filtered = filtered.filter((item) => item.type === filterType) } // Apply search filter if (searchQuery) { const query = searchQuery.toLowerCase() filtered = filtered.filter( (item) => item.title.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query) || item.tags.some((tag) => tag.toLowerCase().includes(query)), ) } // Sort items filtered.sort((a, b) => { switch (sortBy) { case "score": return (b.score || 0) - (a.score || 0) case "duration": return b.duration - a.duration default: return a.timestamp - b.timestamp } }) return filtered }, [previewItems, filterType, searchQuery, sortBy]) // Paginate items const paginatedItems = useMemo(() => { const startIndex = (currentPage - 1) * itemsPerPage return filteredItems.slice(startIndex, startIndex + itemsPerPage) }, [filteredItems, currentPage, itemsPerPage]) const totalPages = Math.ceil(filteredItems.length / itemsPerPage) const handleItemClick = (item: PreviewItem) => { if (enableSelection) { const newSelected = new Set(selectedItems) if (newSelected.has(item.id)) { newSelected.delete(item.id) } else { newSelected.add(item.id) } setSelectedItems(newSelected) const selectedPreviewItems = filteredItems.filter((i) => newSelected.has(i.id)) onSelectionChange?.(selectedPreviewItems) } else { onItemSelect?.(item) } } const handleSelectAll = (checked: boolean) => { if (checked) { const allIds = new Set(filteredItems.map((item) => item.id)) setSelectedItems(allIds) onSelectionChange?.(filteredItems) } else { setSelectedItems(new Set()) onSelectionChange?.([]) } } if (!analysis) { return (

Нет контента для отображения

Загрузите и проанализируйте видео

) } return (
{/* Toolbar */}
setSearchQuery(e.target.value)} className="pl-10 w-64" />
{enableFiltering && ( setFilterType(value)}> Все Сцены Моменты Основное )}
{enableSelection && filteredItems.length > 0 && (
0} onCheckedChange={handleSelectAll} /> {selectedItems.size} из {filteredItems.length}
)}
{/* Content Grid/List */} {currentViewMode === "grid" ? (
{paginatedItems.map((item) => ( handleItemClick(item)} onPlay={() => onItemPlay?.(item)} onDownload={() => onItemDownload?.(item)} onStar={() => onItemStar?.(item)} onShare={() => onItemShare?.(item)} /> ))}
) : (
{paginatedItems.map((item) => ( handleItemClick(item)} onPlay={() => onItemPlay?.(item)} onDownload={() => onItemDownload?.(item)} onStar={() => onItemStar?.(item)} onShare={() => onItemShare?.(item)} /> ))}
)} {/* Pagination */} {totalPages > 1 && (
Страница {currentPage} из {totalPages}
)} {/* Results Summary */}
Показано {paginatedItems.length} из {filteredItems.length} элементов {searchQuery && ` по запросу "${searchQuery}"`}
) } // Preview Card Component for Grid View interface PreviewCardProps { item: PreviewItem isSelected: boolean enableSelection: boolean onClick: () => void onPlay: () => void onDownload: () => void onStar: () => void onShare: () => void } const PreviewCard: FC = ({ item, isSelected, enableSelection, onClick, onPlay, onDownload, onStar, onShare, }) => { return ( {/* Thumbnail */}
{item.title} { // Fallback to placeholder ;(e.target as HTMLImageElement).src = `data:image/svg+xml,${encodeURIComponent( 'Превью', )}` }} /> {/* Overlay Controls */}
{/* Selection Checkbox */} {enableSelection && (
e.stopPropagation()} />
)} {/* Duration Badge */} {formatDuration(item.duration)} {/* Score Badge */} {item.score && ( {Math.round(item.score)} )}
{/* Content */}

{item.title}

{item.description &&

{item.description}

} {/* Tags */}
{item.tags.slice(0, 2).map((tag, index) => ( {tag} ))}
{/* Action Buttons */}
{formatTime(item.timestamp)}
) } // Preview List Item Component for List View const PreviewListItem: FC = ({ item, isSelected, enableSelection, onClick, onPlay, onDownload, onStar, onShare, }) => { return (
{/* Selection Checkbox */} {enableSelection && e.stopPropagation()} />} {/* Thumbnail */}
{item.title} { ;(e.target as HTMLImageElement).src = `data:image/svg+xml,${encodeURIComponent( 'Превью', )}` }} />
{/* Content */}

{item.title}

{item.description && (

{item.description}

)}
{formatTime(item.timestamp)} Длительность: {formatDuration(item.duration)} {item.score && ( {Math.round(item.score)} )}
{/* Tags */}
{item.tags.map((tag, index) => ( {tag} ))}
{/* Action Buttons */}
) } // Utility functions function formatDuration(seconds: number): string { const minutes = Math.floor(seconds / 60) const secs = Math.floor(seconds % 60) return `${minutes}:${secs.toString().padStart(2, "0")}` } function formatTime(seconds: number): string { const minutes = Math.floor(seconds / 60) const secs = Math.floor(seconds % 60) return `${minutes}:${secs.toString().padStart(2, "0")}` }