diff --git a/src/components/home/SecondaryFeatures.jsx b/src/components/home/SecondaryFeatures.jsx index fba12c4c..1719937d 100644 --- a/src/components/home/SecondaryFeatures.jsx +++ b/src/components/home/SecondaryFeatures.jsx @@ -1,6 +1,6 @@ 'use client' -import { useId } from 'react' +import { useEffect, useId, useRef, useState } from 'react' import Image from 'next/image' import { Tab } from '@headlessui/react' import clsx from 'clsx' @@ -48,18 +48,18 @@ const features = [ 'Review recorded student lab sessions.', description: 'We automatically records lab sessions, so you can review them later.', - image: '../../videoproof.mp4', - icon: function InventoryIcon() { + image: '../../videoproof.mp4', + icon: function InventoryIcon() { return ( <> - - - - + + + + ) @@ -71,19 +71,19 @@ const features = [ 'Cloud machines streamed to the browser.', description: 'Easily access cloud machines from your browser, no need to install anything.', - image: '../../terminalproof.mp4', - icon: function ContactsIcon() { + image: '../../terminalproof.mp4', + icon: function ContactsIcon() { return ( <> - - - + + + + - ) }, @@ -123,32 +123,43 @@ function Feature({ feature, isActive, className, ...props }) { } function FeaturesMobile() { + let observer = useRef(null); + + useEffect(() => { + if (!observer.current) { + observer.current = new IntersectionObserver((entries) => { + if (entries[0].intersectionRatio > 0.4) { + entries[0].target.play(); + } else { + entries[0].target.pause(); + } + }, { threshold: [0, 0.5] }); + } + }, []); + return (
{features.map((feature) => (
- - - - + muted + ref={(el) => setTimeout(() => { el && observer.current.observe(el) })} + + autoSave='true' + loop + onLoadedMetadata={(e) => { + e.target.currentTime = 2; // Skip first two seconds + }} + > + + +
))}
@@ -156,69 +167,126 @@ function FeaturesMobile() { } function FeaturesDesktop() { + const observer = useRef(null); + const selectedVideo = useRef(null); + const previousVideo = useRef(null); + const [selectedIndex, _setSelectedIndex] = useState(0); + const selectedIndexRef = useRef(selectedIndex); + const setSelectedIndex = (index) => { + selectedIndexRef.current = index; + _setSelectedIndex(index); + }; + + useEffect(() => { + if (!observer.current) { + observer.current = new IntersectionObserver((entries) => { + if (entries[0].intersectionRatio > 0.4) { + selectedVideo.current?.play(); + } else { + selectedVideo.current?.pause(); + } + }, { threshold: [0, 0.5] }); + } + }, []); + + const restartVideo = () => { + if (typeof window === "undefined") { + return; + } + const vid = document.getElementById("video-" + selectedIndexRef.current); + if (!vid || previousVideo.current == vid) { + return; + } + selectedVideo.current = vid; + vid.currentTime = 0; + if (previousVideo.current !== null) { + vid.play(); + previousVideo.current.pause(); + previousVideo.current.currentTIme = 0; + } + + previousVideo.current = vid; + }; + + const onVideoEnd = () => { + setSelectedIndex((selectedIndex + 1) % features.length); + restartVideo(); + } + return ( - - {({ selectedIndex }) => ( - <> - - {features.map((feature, featureIndex) => ( - - - {feature.name} - - ), - }} - isActive={featureIndex === selectedIndex} - className="relative" - /> - ))} - - -
+ setTimeout(() => el && observer.current?.observe(el) || restartVideo("video-0"))} + className="hidden lg:mt-20 lg:block" + onChange={(index) => { + setSelectedIndex(index); + restartVideo(); + }} + selectedIndex={selectedIndex} + > + {() => { + return ( + <> + {features.map((feature, featureIndex) => ( - -
- - - + feature={{ + ...feature, + name: ( + + + {feature.name} + + ), + }} + isActive={selectedIndex === featureIndex} + className="relative" + /> + ))} + + +
+ {features.map((feature, featureIndex) => ( + +
+ -
-
- ))} -
-
- - - )} + + +
+ + ))} +
+
+ + + ) + }} ) } @@ -235,11 +303,11 @@ export function SecondaryFeatures() {

We're the best platform for teaching cybersecurity.

- +
- - + +