lazy loding

This commit is contained in:
2024-03-25 17:53:35 +05:00
parent a2e2facc79
commit 01f6af2dfa
3 changed files with 105 additions and 38 deletions
+46 -12
View File
@@ -36,6 +36,17 @@ import LabelCard from "@components/CardYear";
import ProjectsSection from "@components/ProjectsSection";
import { motion } from "framer-motion";
const VIDEOS = [
"/videos/features/virtual_tour.mp4",
"/videos/features/nks_infra.mp4",
"/videos/features/uralsky.mp4",
"/videos/features/parametric.mp4",
"/videos/features/render.mp4",
"/videos/features/wish.mp4",
"/videos/features/integra_crm.mp4",
"/videos/features/send.mp4",
];
function getSortedProjects(projects: IProject[]) {
const sorted = [...projects].sort(
(da, db) => getTime(db.releaseDate) - getTime(da.releaseDate)
@@ -87,7 +98,33 @@ export default function App() {
const [setModal] = useModalStore((state) => [state.setModal]);
const [isShownAllProjects, setIsShownAllProjects] = useState<boolean>(false);
const [isBuffering, setIsBuffering] = useState(true);
const featureRef = useRef(null);
const [viewPortEntered, setViewPortEntered] = useState(false);
const featureRefDesktop = useRef<HTMLDivElement>(null);
const featureRefMobile = useRef<HTMLDivElement>(null);
const handleOnViewportFeatureEnter = () => {
if (viewPortEntered) return;
setViewPortEntered(true);
if (!featureRefDesktop.current || !featureRefMobile.current) return;
const videoDesktopRefs = featureRefDesktop.current.children;
const videoMobileRefs = featureRefMobile.current.children;
if (!videoDesktopRefs || !videoMobileRefs) return;
for (let i = 0; i < videoDesktopRefs.length; i++) {
const videoMobileEl = videoDesktopRefs[i] as HTMLVideoElement;
const videoDesktopEl = videoMobileRefs[i] as HTMLVideoElement;
if (videoMobileEl.dataset.src && videoDesktopEl.dataset.src) {
videoDesktopEl.src = videoDesktopEl.dataset.src;
videoMobileEl.src = videoMobileEl.dataset.src;
}
}
setViewPortEntered(true);
};
async function getProjects() {
try {
@@ -336,10 +373,8 @@ export default function App() {
<motion.div
className="xl:grid flex flex-col grid-cols-2 xl:gap-4 sm:gap-10 gap-8 2xl:mb-[200px] sm:mb-[120px] mb-20"
viewport={{ once: true, margin: "-10%" }}
onViewportEnter={() =>
console.log("first", featureRef.current.firstElementChild)
}
viewport={{ margin: "-10%" }}
onViewportEnter={handleOnViewportFeatureEnter}
>
<div className="flex flex-col gap-20">
<div className="xl:flex flex-col grid sm:grid-cols-2 xl:gap-8 gap-3">
@@ -416,14 +451,13 @@ export default function App() {
/> */}
</div>
</div>
<div
className="aspect-video sticky top-[25%] xl:block hidden"
ref={featureRef}
>
<FeatureVideoViewBox video={selectedVideo} />
</div>
<FeatureVideoViewBox
selectedVideo={selectedVideo}
videos={VIDEOS}
featureRef={featureRefDesktop}
/>
<VideoSliderMobile />
<VideoSliderMobile featureRef={featureRefMobile} />
</motion.div>
{/* <Histories /> */}
+52 -23
View File
@@ -1,36 +1,65 @@
import { useEffect, useRef } from "react";
interface FeatureVideoViewBoxProps {
video: string;
selectedVideo: string;
videos: string[];
featureRef: React.LegacyRef<HTMLDivElement>;
}
function FeatureVideoViewBox({ video }: FeatureVideoViewBoxProps) {
function FeatureVideoViewBox({
selectedVideo,
videos,
featureRef,
}: FeatureVideoViewBoxProps) {
// const videoRef = useRef<HTMLVideoElement>(null);
const videoContainerRef = useRef<HTMLDivElement>(null);
// useEffect(() => {
// if (!selectedVideo || !videoContainerRef.current) return;
// const videoEl = document.createElement("video");
// videoEl.src = selectedVideo;
// videoEl.muted = true;
// videoEl.autoplay = true;
// videoEl.loop = true;
// videoEl.playsInline = true;
// videoEl.preload = "metadata";
// videoEl.classList.add("absolute", "h-fit");
// // videoEl.onloadeddata = () => console.log("onloadeddata");
// videoContainerRef.current.appendChild(videoEl);
// if (videoContainerRef.current.childElementCount > 1) {
// setTimeout(() => {
// videoContainerRef.current?.firstElementChild?.remove();
// }, 5000);
// }
// }, [selectedVideo]);
useEffect(() => {
if (!video || !videoContainerRef.current) return;
return () => {};
}, [selectedVideo]);
const videoEl = document.createElement("video");
videoEl.src = video;
videoEl.muted = true;
videoEl.autoplay = true;
videoEl.loop = true;
videoEl.playsInline = true;
videoEl.preload = "metadata";
videoEl.classList.add("absolute", "h-fit");
// videoEl.onloadeddata = () => console.log("onloadeddata");
videoContainerRef.current.appendChild(videoEl);
if (videoContainerRef.current.childElementCount > 1) {
setTimeout(() => {
videoContainerRef.current?.firstElementChild?.remove();
}, 5000);
}
}, [video]);
return <div ref={videoContainerRef} className="relative h-fit"></div>;
return (
<div className="aspect-video sticky top-[25%] xl:block hidden">
<div ref={featureRef} className="relative h-fit">
{videos.map((video) => (
<video
data-src={video}
key={video}
muted
autoPlay
loop
playsInline
preload="metadata"
className={`absolute h-fit ${
selectedVideo === video ? "block" : "hidden"
}`}
/>
))}
</div>
</div>
);
}
export default FeatureVideoViewBox;
+7 -3
View File
@@ -6,7 +6,11 @@ import ArrowLeftIcon from "./icons/ArrowLeftIcon";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import { useSwipeable } from "react-swipeable";
function VideoSliderMobile() {
interface IVideoSliderMobile {
featureRef: React.LegacyRef<HTMLDivElement>;
}
function VideoSliderMobile({ featureRef }: IVideoSliderMobile) {
const [items] = useState<any[]>([
{
title: "Виртуальный тур по жилому комплексу",
@@ -102,7 +106,7 @@ function VideoSliderMobile() {
className="xl:hidden flex flex-col sm:gap-6 gap-4 border-b border-[#3D425C] pb-5"
>
<div
// ref={videosContainerRef}
ref={featureRef}
className={`relative flex sm:gap-[88px] items-start transition-all duration-500`}
style={{ left: `-${activeIndex * 100}%` }}
>
@@ -110,7 +114,7 @@ function VideoSliderMobile() {
<motion.video
key={index}
ref={videoRefs[index]}
src={item.video}
data-src={item.video}
muted
loop
playsInline