Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianhajdin authored Mar 15, 2024
1 parent 2504c9b commit ecdfbfa
Showing 1 changed file with 346 additions and 0 deletions.
346 changes: 346 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,352 @@ export const footerLinks = [

</details>

<details>
<summary><code>Lights.jsx</code></summary>

```javascript
import { Environment, Lightformer } from "@react-three/drei";

const Lights = () => {
return (
// group different lights and lightformers. We can use group to organize lights, cameras, meshes, and other objects in the scene.
<group name="lights">
{/**
* @description Environment is used to create a background environment for the scene
* https://github.com/pmndrs/drei?tab=readme-ov-file#environment
*/}
<Environment resolution={256}>
<group>
{/**
* @description Lightformer used to create custom lights with various shapes and properties in a 3D scene.
* https://github.com/pmndrs/drei?tab=readme-ov-file#lightformer
*/}
<Lightformer
form="rect"
intensity={10}
position={[-1, 0, -10]}
scale={10}
color={"#495057"}
/>
<Lightformer
form="rect"
intensity={10}
position={[-10, 2, 1]}
scale={10}
rotation-y={Math.PI / 2}
/>
<Lightformer
form="rect"
intensity={10}
position={[10, 0, 1]}
scale={10}
rotation-y={Math.PI / 2}
/>
</group>
</Environment>

{/**
* @description spotLight is used to create a light source positioned at a specific point
* in the scene that emits light in a specific direction.
* https://threejs.org/docs/#api/en/lights/SpotLight
*/}
<spotLight
position={[-2, 10, 5]}
angle={0.15}
penumbra={1} // the penumbra is the soft edge of a shadow cast by a point light
decay={0} // the amount the light dims as it moves away from the source
intensity={Math.PI * 0.2} // the light intensity
color={"#f8f9fa"}
/>
<spotLight
position={[0, -25, 10]}
angle={0.15}
penumbra={1}
decay={0}
intensity={Math.PI * 0.2}
color={"#f8f9fa"}
/>
<spotLight
position={[0, 15, 5]}
angle={0.15}
penumbra={1}
decay={0.1}
intensity={Math.PI * 3}
/>
</group>
);
};

export default Lights;
```
</details>

<details>
<summary><code>materials</code></summary>

```javascript
useEffect(() => {
Object.entries(materials).map((material) => {
// these are the material names that can't be changed color
if (
material[0] !== "zFdeDaGNRwzccye" &&
material[0] !== "ujsvqBWRMnqdwPx" &&
material[0] !== "hUlRcbieVuIiOXG" &&
material[0] !== "jlzuBkUzuJqgiAK" &&
material[0] !== "xNrofRCqOXXHVZt"
) {
material[1].color = new THREE.Color(props.item.color[0]);
}
material[1].needsUpdate = true;
});
}, [materials, props.item]);
```

</details>

<details>
<summary><code>VideoCarousel.jsx</code></summary>

```javascript
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/all";
gsap.registerPlugin(ScrollTrigger);
import { useEffect, useRef, useState } from "react";

import { hightlightsSlides } from "../constants";
import { pauseImg, playImg, replayImg } from "../utils";

const VideoCarousel = () => {
const videoRef = useRef([]);
const videoSpanRef = useRef([]);
const videoDivRef = useRef([]);

// video and indicator
const [video, setVideo] = useState({
isEnd: false,
startPlay: false,
videoId: 0,
isLastVideo: false,
isPlaying: false,
});

const [loadedData, setLoadedData] = useState([]);
const { isEnd, isLastVideo, startPlay, videoId, isPlaying } = video;

useGSAP(() => {
// slider animation to move the video out of the screen and bring the next video in
gsap.to("#slider", {
transform: `translateX(${-100 * videoId}%)`,
duration: 2,
ease: "power2.inOut", // show visualizer https://gsap.com/docs/v3/Eases
});

// video animation to play the video when it is in the view
gsap.to("#video", {
scrollTrigger: {
trigger: "#video",
toggleActions: "restart none none none",
},
onComplete: () => {
setVideo((pre) => ({
...pre,
startPlay: true,
isPlaying: true,
}));
},
});
}, [isEnd, videoId]);

useEffect(() => {
let currentProgress = 0;
let span = videoSpanRef.current;

if (span[videoId]) {
// animation to move the indicator
let anim = gsap.to(span[videoId], {
onUpdate: () => {
// get the progress of the video
const progress = Math.ceil(anim.progress() * 100);

if (progress != currentProgress) {
currentProgress = progress;

// set the width of the progress bar
gsap.to(videoDivRef.current[videoId], {
width:
window.innerWidth < 760
? "10vw" // mobile
: window.innerWidth < 1200
? "10vw" // tablet
: "4vw", // laptop
});

// set the background color of the progress bar
gsap.to(span[videoId], {
width: `${currentProgress}%`,
backgroundColor: "white",
});
}
},

// when the video is ended, replace the progress bar with the indicator and change the background color
onComplete: () => {
if (isPlaying) {
gsap.to(videoDivRef.current[videoId], {
width: "12px",
});
gsap.to(span[videoId], {
backgroundColor: "#afafaf",
});
}
},
});

if (videoId == 0) {
anim.restart();
}

// update the progress bar
const animUpdate = () => {
anim.progress(
videoRef.current[videoId].currentTime /
hightlightsSlides[videoId].videoDuration
);
};

if (isPlaying) {
// ticker to update the progress bar
gsap.ticker.add(animUpdate);
} else {
// remove the ticker when the video is paused (progress bar is stopped)
gsap.ticker.remove(animUpdate);
}
}
}, [videoId, startPlay]);

useEffect(() => {
if (loadedData.length > 3) {
if (!isPlaying) {
videoRef.current[videoId].pause();
} else {
startPlay && videoRef.current[videoId].play();
}
}
}, [startPlay, videoId, isPlaying, loadedData]);

// vd id is the id for every video until id becomes number 3
const handleProcess = (type, i) => {
switch (type) {
case "video-end":
setVideo((pre) => ({ ...pre, isEnd: true, videoId: i + 1 }));
break;

case "video-last":
setVideo((pre) => ({ ...pre, isLastVideo: true }));
break;

case "video-reset":
setVideo((pre) => ({ ...pre, videoId: 0, isLastVideo: false }));
break;

case "pause":
setVideo((pre) => ({ ...pre, isPlaying: !pre.isPlaying }));
break;

case "play":
setVideo((pre) => ({ ...pre, isPlaying: !pre.isPlaying }));
break;

default:
return video;
}
};

const handleLoadedMetaData = (i, e) => setLoadedData((pre) => [...pre, e]);

return (
<>
<div className="flex items-center">
{hightlightsSlides.map((list, i) => (
<div key={list.id} id="slider" className="sm:pr-20 pr-10">
<div className="video-carousel_container">
<div className="w-full h-full flex-center rounded-3xl overflow-hidden bg-black">
<video
id="video"
playsInline={true}
className={`${
list.id === 2 && "translate-x-44"
} pointer-events-none`}
preload="auto"
muted
ref={(el) => (videoRef.current[i] = el)}
onEnded={() =>
i !== 3
? handleProcess("video-end", i)
: handleProcess("video-last")
}
onPlay={() =>
setVideo((pre) => ({ ...pre, isPlaying: true }))
}
onLoadedMetadata={(e) => handleLoadedMetaData(i, e)}
>
<source src={list.video} type="video/mp4" />
</video>
</div>

<div className="absolute top-12 left-[5%] z-10">
{list.textLists.map((text, i) => (
<p key={i} className="md:text-2xl text-xl font-medium">
{text}
</p>
))}
</div>
</div>
</div>
))}
</div>

<div className="relative flex-center mt-10">
<div className="flex-center py-5 px-7 bg-gray-300 backdrop-blur rounded-full">
{videoRef.current.map((_, i) => (
<span
key={i}
className="mx-2 w-3 h-3 bg-gray-200 rounded-full relative cursor-pointer"
ref={(el) => (videoDivRef.current[i] = el)}
>
<span
className="absolute h-full w-full rounded-full"
ref={(el) => (videoSpanRef.current[i] = el)}
/>
</span>
))}
</div>

<button className="control-btn">
<img
src={isLastVideo ? replayImg : !isPlaying ? playImg : pauseImg}
alt={isLastVideo ? "replay" : !isPlaying ? "play" : "pause"}
onClick={
isLastVideo
? () => handleProcess("video-reset")
: !isPlaying
? () => handleProcess("play")
: () => handleProcess("pause")
}
/>
</button>
</div>
</>
);
};

export default VideoCarousel;

```

</details>

<details>
<summary><code>utils/index.js</code></summary>

Expand Down

0 comments on commit ecdfbfa

Please sign in to comment.