import { useEffect, useReducer, useRef, useState } from 'react'; import { MiniTitle } from '../../ui/MiniTitle'; import { useWindowWidth } from '../../hooks/useWindowWidth'; import { Title } from '../../ui/Title'; import { useSwipeable } from 'react-swipeable'; import { ArrowLeftIcon } from '../icons/ArrowLeftIcon'; import { ArrowRightIcon } from '../icons/ArrowRightIcon'; import { PauseIcon } from '../icons/PauseIcon'; import { PlayIcon } from '../icons/PlayIcon'; import useStateRef from 'react-usestateref'; enum Media { video, img, } interface IProject { src: TMedia extends Media.img ? string : string[]; title: string; tags: string[]; media?: TMedia; } export function Projects() { return (
<span className="text-gradient">Большой опыт в работе</span> с промышленными предприятиями и учебными заведениями , { src: 'src/assets/projects/plane.png', tags: ['Симулятор', 'VR-приложение'], title: 'L 410 NG Aircraft', media: Media.img, }, { src: 'src/assets/projects/hangar.png', tags: ['Симулятор', 'VR-приложение'], title: 'Сборка-разборка вертолётного двигателя', media: Media.img, }, { src: 'src/assets/projects/trains.png', tags: ['Симулятор', 'VR-приложение'], title: 'Тренажер РЖД: ЭП2Д, Иволга, ЭП20, ТЭ33А, ТЭМ2', media: Media.img, }, { src: 'src/assets/projects/laboratory.png', tags: ['Симулятор', 'VR-приложение'], title: 'Учебная лаборатория определения жирности молока', media: Media.img, }, { src: 'src/assets/projects/train_big.jpg', tags: ['Симулятор'], title: 'Симулятор машиниста', media: Media.img, }, ]} />
); } function Project({ src, title, tags, media }: IProject) { const [buffering, setBuffering] = useState(true); const [playing, setPlaying, playingRef] = useStateRef(false); const videoRef = useRef(null); useEffect(() => console.log(buffering), [buffering]); useEffect(() => console.log(playingRef), [playingRef]); useEffect(() => console.log(playing), [playing]); return (
{media === Media.img ? (
) : (
); } function Slider({ projects }: { projects: IProject[] }) { const width = useWindowWidth(); const baseOffset = width >= 1024 ? width * 0.39 : width >= 640 ? width * 0.67 : width - 20; const [sliderOffset, setSliderOffset] = useState(-baseOffset); const [slide, setSlide] = useState(0); const [isAnimating, setIsAnimating] = useState(false); const ref = useRef(null); const [order, dispatch] = useReducer( (state: typeof projects, action: string) => { switch (action) { case 'prev': setSliderOffset(prev => prev - baseOffset); return [state[state.length - 5], ...state.slice(0, -1)]; case 'next': setSliderOffset(prev => prev + baseOffset); return [...state.slice(1), state[4]]; default: return state; } }, [ projects[projects.length - 2], projects[projects.length - 1], ...projects, projects[0], projects[1], ], ); const handlers = useSwipeable({ onSwipedLeft: () => { if (!isAnimating) { setIsAnimating(true); setSlide(prev => (prev === order.length - 5 ? 0 : prev + 1)); dispatch('next'); } }, onSwipedRight: () => { if (!isAnimating) { setIsAnimating(true); setSlide(prev => (prev === 0 ? order.length - 5 : prev - 1)); dispatch('prev'); } }, trackMouse: true, preventScrollOnSwipe: true, touchEventOptions: { passive: false }, }); useEffect(() => { setSliderOffset(-baseOffset * 2); }, [order, baseOffset, slide]); useEffect(() => { const refValue = ref.current; refValue?.addEventListener('transitionend', () => { setIsAnimating(false); }); return () => refValue?.removeEventListener('transitionend', () => setIsAnimating(false), ); }, [sliderOffset, order, slide]); return (
{order.map((project, index) => ( ))}
); }