logo icon

OKSANA

KOROBANOVA

man in black polo shirt holding black video camera
Back to all posts

A row of animated videos

3 HTML5 videos in a row with animation and autoplay on hover. On click opens a full YouTube video in a dialog


Date:


animated video gif
1//  components/html5Video.js
2
3const Html5Video = ({
4  item: { coverImg, title, description, videoUrl, mp4Video, webmVideo },
5  showFullVideo,
6}) => {
7  const theme = useTheme();
8  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
9  const hasTouch = isTouchDevice();
10
11  const playerRef = useRef();
12  const coverRef = useRef();
13  const playerContainerRef = useRef();
14
15  // currentTime
16  const playOnHover = () => {
17    // 1. hideCoverImg
18    coverRef.current.style.zIndex = 0;
19    coverRef.current.style.opacity = 0;
20    // 2. animate container
21    playerContainerRef.current.style.width = ACTIVE_VIDEO_WIDTH;
22    // 3. play video
23    playerRef.current.play();
24  };
25  const onMouseLeave = () => {
26    // 1. pause video and reset time
27    playerRef.current.pause();
28    playerRef.current.currentTime = 0;
29    // 2. container
30    playerContainerRef.current.style.width = INITIAL_VIDEO_WIDTH;
31    // 3. show cover img
32    coverRef.current.style.zIndex = 1;
33    coverRef.current.style.opacity = 1;
34  };
35
36  return (
37    <Box
38      ref={playerContainerRef}
39      sx={styles.videoBlock}
40      onMouseEnter={isMobile || hasTouch ? undefined : () => playOnHover()}
41      onMouseLeave={isMobile || hasTouch ? undefined : () => onMouseLeave()}
42      onClick={() => showFullVideo(videoUrl)}>
43      <Box
44        ref={coverRef}
45        sx={{
46          ...styles.coverBlock,
47          backgroundImage: `url(${coverImg || videoUrl})`,
48        }}>
49        <Box sx={styles.title}>{title}</Box>
50        <Box sx={styles.description}>{description}</Box>
51      </Box>
52
53      {!isMobile && !hasTouch && (
54        <Box sx={styles.videoWrapper}>
55          <video
56            ref={playerRef}
57            playsInline
58            loop
59            muted
60            preload='true'
61            style={{
62              width: '100%',
63              height: '100%',
64              position: 'absolute',
65              objectFit: 'cover',
66              top: '50%',
67              left: '50%',
68              transform: 'translate(-50%,-50%)',
69              borderRadius: '9px',
70            }}>
71            {mp4Video && <source type='video/mp4' src={mp4Video} />}
72            {webmVideo && <source type='video/webm' src={webmVideo} />}
73            Your browser does not support HTML5 video tag.
74          </video>
75        </Box>
76      )}
77    </Box>
78  );
79};
80
81Html5Video.propTypes = {
82  item: PropTypes.object.isRequired,
83};
84
85export default Html5Video;

1// components/youtubeEmbed.js
2
3const YoutubeEmbed = ({ embedId }) => (
4  <Box sx={styles.videoContainer}>
5    <iframe
6      src={`https://www.youtube.com/embed/${embedId}`}
7      frameBorder='0'
8      allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
9      allowFullScreen
10    />
11  </Box>
12);
13
14YoutubeEmbed.propTypes = {
15  embedId: PropTypes.string.isRequired,
16};
17
18export default YoutubeEmbed;

1// containers/videoGallery.js
2
3const VideoGallery = ({ items = [] }) => {
4  const theme = useTheme();
5  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
6
7  const [fullVideo, setFullVideo] = useState(null);
8  const showFullVideo = (embedCode) => {
9    setFullVideo(embedCode);
10  };
11  const closeFullVideo = () => {
12    setFullVideo(null);
13  };
14
15  return (
16    <Box sx={styles.section} component='section'>
17      <Box sx={styles.container}>
18        <Box sx={styles.content}>
19          {items.map((item) => {
20            return (
21              <Html5Video
22                key={item.title}
23                item={item}
24                showFullVideo={showFullVideo}
25              />
26            );
27          })}
28        </Box>
29      </Box>
30      {!!fullVideo && (
31        <Dialog
32          fullScreen={isMobile}
33          fullWidth
34          maxWidth='md'
35          open
36          onClose={closeFullVideo}
37          sx={styles.dialog}>
38          {isMobile && (
39            <IconButton sx={styles.closeBtn} onClick={closeFullVideo}>
40              <CloseIcon />
41            </IconButton>
42          )}
43          <YoutubeEmbed embedId={fullVideo} />
44        </Dialog>
45      )}
46    </Box>
47  );
48};
49
50VideoGallery.propTypes = {
51  items: PropTypes.array.isRequired,
52};
53
54export default VideoGallery;