let isTouchUsed = false; let isResetWatched = false; /** Хранит id карточки с активным превью: играет только одно, запуск нового гасит предыдущее. */ export const useVideoPreview = () => { const activePreviewId = useState('active-video-preview', () => null); const router = useRouter(); const stopPreview = () => { activePreviewId.value = null; }; /** * Ставится один раз при первом превью. Гасит его на любом касании страницы (слушатель на capture-фазе, * поэтому тап по другой карточке сначала гасит текущее превью, а потом запускает своё) и на старте любого перехода — * чтобы при уходе на страницу видео превью с индикатором не доживало до смены роута. */ const watchPreviewReset = () => { if (isResetWatched) return; isResetWatched = true; document.addEventListener('touchstart', stopPreview, { capture: true, passive: true }); router.beforeEach(stopPreview); }; const startPreviewByHover = (id: string) => { if (isTouchUsed) return; watchPreviewReset(); activePreviewId.value = id; }; /** На тач-устройствах превью живёт до запуска следующего, поэтому гасим только по уходу мыши. */ const stopPreviewByHover = (id: string) => { if (isTouchUsed) return; if (activePreviewId.value === id) activePreviewId.value = null; }; /** Тач-устройства дублируют тап синтетическими mouse-событиями — с первого касания ховерный путь глушим. */ const startPreviewByTouch = (id: string) => { isTouchUsed = true; watchPreviewReset(); activePreviewId.value = id; }; return { activePreviewId, startPreviewByHover, stopPreviewByHover, startPreviewByTouch, }; };