From 9eb41fcb0a65048ae950f49660be2c14b97ee8dc Mon Sep 17 00:00:00 2001 From: Sayyed Sharuk Date: Fri, 17 Nov 2023 19:25:31 +0530 Subject: [PATCH] Intersection Observer --- README.md | 4 ++ src/components/AboutPage/AboutCard.tsx | 7 +++- src/components/AboutPage/DescAboutPage.tsx | 12 ++++-- src/components/Headings/BigHeading.tsx | 10 +++-- src/components/Headings/MdHeading.tsx | 9 +++- src/components/HomePage/DescHome.tsx | 12 ++++-- src/components/HomePage/IconButtonComp.tsx | 48 +++++----------------- src/hooks/useIntersectionObs.ts | 26 ++++++++++++ 8 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 src/hooks/useIntersectionObs.ts diff --git a/README.md b/README.md index ca1f8bc..ae7d807 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ - Day 20: Contact Form Service Added, and added Validations. +- Day 21: Added Intersection Observer Hook, now we re-animate elements. + ## My Learnings - Basic types @@ -50,6 +52,8 @@ - Interfaces, and its inheritance with classes / OOPS - Generic types - Type Combinations using "&", "|" +- Classes, Abstraction, Inheritance, Encapsulation using TypeScript features. - Type Inference - Usage of "unknown" type than "any" type. - Handling React Components and Contexts with TypeScript. +- Handling Ref's with TypeScript diff --git a/src/components/AboutPage/AboutCard.tsx b/src/components/AboutPage/AboutCard.tsx index a33e0db..21f5f89 100644 --- a/src/components/AboutPage/AboutCard.tsx +++ b/src/components/AboutPage/AboutCard.tsx @@ -4,18 +4,23 @@ import DescAboutPage from "./DescAboutPage"; import ContributionList from "./ContributionList"; import { fadeBottom } from "../../animations/FadeAnimations"; import ResumeButton from "./ResumeButton"; +import { RefObject, useRef } from "react"; +import useIntersectionObserver from "../../hooks/useIntersectionObs"; const AboutCard = () => { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( { fontSize={["12px", "14px"]} mt={["60px", "60px", "0px"]} > - Full-stack developer with a focus on building and deploying user-friendly, high-performance web applications. Expertise in both front-end and back-end development, with a - strong understanding of design patterns and best practices. Ability to work independently and as part of a team to deliver high-quality products. + Full-stack developer with a focus on building and deploying user-friendly, high-performance web applications. Expertise in both + front-end and back-end development, with a strong understanding of design patterns and best practices. Ability to work independently + and as part of a team to deliver high-quality products. ); }; diff --git a/src/components/Headings/BigHeading.tsx b/src/components/Headings/BigHeading.tsx index d1e4bef..0f1cab0 100644 --- a/src/components/Headings/BigHeading.tsx +++ b/src/components/Headings/BigHeading.tsx @@ -1,17 +1,21 @@ import { Flex, Text } from "@chakra-ui/react"; import { HeadingProps } from "../../TYPES"; import { fadeLeft, fadeRight } from "../../animations/FadeAnimations"; +import useIntersectionObserver from "../../hooks/useIntersectionObs"; +import { RefObject, useRef } from "react"; const BigHeading = ({ title1, title2 }: HeadingProps) => { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( - + { fontWeight={600} opacity={0} transition={"500ms"} - animation={`${fadeRight} 1s ease-out 500ms forwards`} + animation={isIntersecting ? `${fadeRight} 1s ease-out 500ms forwards` : "none"} textShadow={["none", "3px 3px 0px #fff", "4px 4px 0px #fff"]} fontSize={["34px", "40px", "64px", "86px", "108px"]} color={"#006aFF"} diff --git a/src/components/Headings/MdHeading.tsx b/src/components/Headings/MdHeading.tsx index a6a94f1..4975e0a 100644 --- a/src/components/Headings/MdHeading.tsx +++ b/src/components/Headings/MdHeading.tsx @@ -2,8 +2,12 @@ import { Flex, Highlight, Text } from "@chakra-ui/react"; import { HeadingProps } from "../../TYPES"; import { fadeTop } from "../../animations/FadeAnimations"; import { ScalePing } from "../../animations/ScaleAnimations"; +import { RefObject, useRef } from "react"; +import useIntersectionObserver from "../../hooks/useIntersectionObs"; const MdHeading = ({ title1, title2 }: HeadingProps) => { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( { transition={"500ms"} color={"#006aff"} my={"4"} + ref={animRef} cursor={"pointer"} rounded={"full"} - animation={`${fadeTop} 1s ease-in forwards `} - _active={{ transform: "translateY(-20px)", animation: `${ScalePing} 1s ease-in-out` }} + animation={isIntersecting ? `${fadeTop} 1s ease-in forwards` : "none"} + _active={{ transform: "translateY(-20px)", animation: isIntersecting ? `${ScalePing} 1s ease-in-out` : "none" }} > {`${title1} ${title2}`} diff --git a/src/components/HomePage/DescHome.tsx b/src/components/HomePage/DescHome.tsx index a4b80d5..2c2723c 100644 --- a/src/components/HomePage/DescHome.tsx +++ b/src/components/HomePage/DescHome.tsx @@ -1,10 +1,15 @@ import { Text } from "@chakra-ui/react"; import { fadeTop } from "../../animations/FadeAnimations"; +import { RefObject, useRef } from "react"; +import useIntersectionObserver from "../../hooks/useIntersectionObs"; const DescHome = () => { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( { fontSize={["12px", "14px", "16px", "18px"]} m={["4", "8"]} letterSpacing={"2px"} - animation={`${fadeTop} 1s ease-out forwards`} + animation={isIntersecting ? `${fadeTop} 1s ease-out forwards` : "none"} > - A Full Stack Developer who enjoys solving problems and building quality projects. With a diverse set of skills and technologies, Can develop robust and efficient products. - Keep up with the latest advancements in the field, and work well with teams to deliver the best possible results. + A Full Stack Developer who enjoys solving problems and building quality projects. With a diverse set of skills and technologies, Can + develop robust and efficient products. Keep up with the latest advancements in the field, and work well with teams to deliver the best + possible results. ); }; diff --git a/src/components/HomePage/IconButtonComp.tsx b/src/components/HomePage/IconButtonComp.tsx index 23503a6..79b6593 100644 --- a/src/components/HomePage/IconButtonComp.tsx +++ b/src/components/HomePage/IconButtonComp.tsx @@ -2,61 +2,35 @@ import { IconButton, Tooltip } from "@chakra-ui/react"; import { polishAnim } from "../../animations/NavbarAnimations"; import { SocialBtnType } from "../../TYPES"; import { fadeTop } from "../../animations/FadeAnimations"; +import { RefObject, useRef } from "react"; +import useIntersectionObserver from "../../hooks/useIntersectionObs"; -const IconButtonComp = ({ - link, - tooltip, - label, - icon, - onClick, - delay, -}: SocialBtnType) => { +const IconButtonComp = ({ link, tooltip, label, icon, onClick, delay }: SocialBtnType) => { return link ? ( - + ) : ( - + ); }; export default IconButtonComp; -const IconButtonHome = ({ - label, - icon, - onClick, - tooltip, - delay, -}: SocialBtnType) => { +const IconButtonHome = ({ label, icon, onClick, tooltip, delay }: SocialBtnType) => { + const animRef: RefObject = useRef(null); + const isIntersecting = useIntersectionObserver(animRef); return ( - + , options = {}) => { + const [isIntersecting, setIsIntersecting] = useState(false); + const observer = useRef(null); + + useEffect(() => { + if (ref.current) { + observer.current = new IntersectionObserver(([entry]) => { + setIsIntersecting(entry.isIntersecting); + }, options); + + observer.current.observe(ref.current); + + return () => { + if (observer.current) { + observer.current.disconnect(); + } + }; + } + }, [ref, options]); + + return isIntersecting; +}; + +export default useIntersectionObserver;