import { memo, useMemo } from "react" import { useFavorites } from "@/features/app-state" import { MediaPreview } from "@/features/browser" import { MediaFile } from "@/features/media" import { useProjectSettings } from "@/features/project-settings/hooks/use-project-settings" import { cn } from "@/lib/utils" import { FileMetadata } from "./file-metadata" /** * Интерфейс свойств компонента MediaItem */ interface MediaItemProps { /** Медиа-файл для отображения */ file: MediaFile /** Индекс файла в списке */ index: number /** Режим отображения (list, grid, thumbnails) */ viewMode: string /** Размер превью */ previewSize: number } /** * Компонент для отображения отдельного медиа-файла в различных режимах просмотра * * @param {MediaItemProps} props - Свойства компонента * @returns {JSX.Element} Компонент медиа-элемента */ export const MediaItem = memo( ({ file, viewMode, previewSize }) => { const { favorites } = useFavorites() // Хук для работы с избранным const { settings } = useProjectSettings() // Получаем настройки проекта // Стабильный ключ файла const fileId = useMemo(() => file.id || file.path || file.name, [file.id, file.path, file.name]) // Мемоизируем проверку избранного const isAdded = useMemo(() => favorites.media.some((item) => item.id === file.id), [favorites.media, file.id]) // Получаем соотношение сторон из настроек проекта const projectAspectRatio = useMemo(() => { const { width, height } = settings.aspectRatio.value return width / height }, [settings.aspectRatio]) // Размер превью для режима list - уменьшаем высоту const listPreviewSize = useMemo(() => { // Для режима list используем фиксированную небольшую высоту return previewSize }, [viewMode, previewSize]) // Мемоизируем стили для grid режима const gridStyles = useMemo( () => ({ width: `${(previewSize * projectAspectRatio + 2).toFixed(0)}px`, }), [previewSize, projectAspectRatio], ) // Мемоизируем размер шрифта const fontSize = useMemo(() => (previewSize > 150 ? "13px" : "12px"), [previewSize]) // Мемоизируем базовые классы const baseClasses = useMemo(() => (isAdded ? "pointer-events-none" : ""), [isAdded]) if (viewMode === "list") { return (
) } if (viewMode === "grid") { return (
{file.name}
) } if (viewMode === "thumbnails") { return (
) } return null }, (prevProps, nextProps) => { // Кастомная функция сравнения для более точного контроля return ( prevProps.file.id === nextProps.file.id && prevProps.file.isLoadingMetadata === nextProps.file.isLoadingMetadata && prevProps.file.probeData === nextProps.file.probeData && prevProps.file.thumbnailPath === nextProps.file.thumbnailPath && prevProps.viewMode === nextProps.viewMode && prevProps.previewSize === nextProps.previewSize ) }, ) MediaItem.displayName = "MediaItem"