import { Check, Plus, X } from "lucide-react" import { memo, useCallback, useEffect, useRef, useState } from "react" import { useTranslation } from "react-i18next" import { useResources } from "@/features/resources" import { ResourceType, TimelineResource } from "@/features/resources/types" import { cn } from "@/lib/utils" interface AddMediaButtonProps { resource: TimelineResource size: number type: ResourceType } /** * Кнопка для добавления/удаления медиафайла на таймлайн * * Функционал: * - Отображает кнопку добавления медиафайла на таймлайн * - Кнопка добавления с состояниями (добавлено/не добавлено) * - При наведении на добавленный элемент меняется на кнопку удаления * - Темная тема для UI элементов * - Плавная анимация при добавлении файла * - Задержка перед отображением кнопки удаления после добавления файла * * @param resource - Объект медиафайла * @param type - Тип ресурса (media, music, subtitles и т.д.) * @param size - Размер кнопки (по умолчанию 150) */ export const AddMediaButton = memo(function AddMediaButton({ resource, size = 150, type = "media", }: AddMediaButtonProps) { const { t } = useTranslation() const [isHovering, setIsHovering] = useState(false) const [isRecentlyAdded, setIsRecentlyAdded] = useState(false) const timerRef = useRef(null) const prevIsAddedRef = useRef(false) const { addMedia, addMusic, addEffect, addFilter, addTransition, addSubtitle, addTemplate, addStyleTemplate, removeResource, isAdded, } = useResources() // Обновляем состояние при изменении isAdded useEffect(() => { if (isAdded(resource.id, type) !== prevIsAddedRef.current) { // Если файл добавлен, устанавливаем флаг isRecentlyAdded if (isAdded(resource.id, type)) { setIsRecentlyAdded(true) // Очищаем предыдущий таймер, если он есть if (timerRef.current) { clearTimeout(timerRef.current) } // Через 1 секунду сбрасываем флаг timerRef.current = setTimeout(() => { setIsRecentlyAdded(false) timerRef.current = null }, 1000) } else { // Если файл удален, сбрасываем флаг isRecentlyAdded setIsRecentlyAdded(false) // Очищаем таймер if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } } // Обновляем предыдущее значение isAdded prevIsAddedRef.current = isAdded(resource.id, type) } // Очищаем таймер при размонтировании компонента return () => { if (timerRef.current) { clearTimeout(timerRef.current) timerRef.current = null } } }, [isAdded]) // Принудительно обновляем состояние при монтировании компонента useEffect(() => { // Если элемент уже добавлен при монтировании компонента if (isAdded(resource.id, type)) { setIsRecentlyAdded(true) prevIsAddedRef.current = true // Через 1 секунду сбрасываем флаг const timer = setTimeout(() => { setIsRecentlyAdded(false) }, 1000) return () => clearTimeout(timer) } }, [isAdded]) // Определяем, можно ли показывать кнопку удаления // Не показываем кнопку удаления в течение 3 секунд после добавления const canShowRemoveButton = !isRecentlyAdded const handleToggleFavorite = useCallback( (e: React.MouseEvent) => { e.stopPropagation() e.preventDefault() if (isAdded(resource.id, type) && canShowRemoveButton) { // Удаляем из добавленных void removeResource(resource.id) } else if (!isAdded(resource.id, type) && isHovering) { // Добавляем в добавленные в зависимости от типа switch (resource.type) { case "media": void addMedia(resource.file) break case "music": void addMusic(resource.file) break case "effect": void addEffect(resource.effect) break case "filter": void addFilter(resource.filter) break case "transition": void addTransition(resource.transition) break case "subtitle": void addSubtitle(resource.style) break case "template": void addTemplate(resource.template) break case "styleTemplate": void addStyleTemplate(resource.template) break default: console.warn(`Unknown resource type: ${(resource as any).type}`) } // Немедленно обновляем визуальное состояние setIsRecentlyAdded(true) } }, [ isAdded, isHovering, canShowRemoveButton, removeResource, addMedia, addMusic, addEffect, addFilter, addTransition, addSubtitle, addTemplate, addStyleTemplate, resource, type, ], ) return ( ) })