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.
-
+
-
-
+
+