Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions src/components/section.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { memo, ReactNode, useEffect, useRef, useState } from "react";
import { memo, ReactNode, useEffect, useRef } from "react";

export const Section = memo(
({
Expand All @@ -12,22 +12,30 @@ export const Section = memo(
title: string;
children: ReactNode;
}) => {
const [isVisible, setIsVisible] = useState(false);
const dataRef = useRef<HTMLElement | null>(null);
const itemRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
const getScreenWidth = () =>
const screenWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;

// ⚡ Optimization: Use direct DOM manipulation instead of React state to toggle classes.
// This prevents unnecessary re-renders of the entire section and its children
// every time it enters or leaves the viewport.
const observer = new IntersectionObserver(
([entry]) => {
setIsVisible(entry.isIntersecting);
if (itemRef.current) {
if (entry.isIntersecting) {
itemRef.current.classList.add("pop-up-child");
} else {
itemRef.current.classList.remove("pop-up-child");
}
}
},
{
rootMargin: `${getScreenWidth() <= 700 ? "-100px" : "-250px"}`,
rootMargin: screenWidth <= 700 ? "-100px" : "-250px",
},
);

Expand All @@ -43,16 +51,6 @@ export const Section = memo(
};
}, []);

useEffect(() => {
if (itemRef.current) {
if (isVisible) {
itemRef.current.classList.add("pop-up-child");
} else {
itemRef.current.classList.remove("pop-up-child");
}
}
}, [isVisible]);

return (
<section id={id} className="section scroll-mt-48" ref={dataRef}>
<div className="flex items-center gap-4 mb-8">
Expand Down
27 changes: 20 additions & 7 deletions src/components/sections/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import React, { useEffect, useRef, useState, memo } from "react";
import { TypeAnimation } from "react-type-animation";

const HeroSection = memo(() => {
const [isHome, setIsHome] = useState(true);
const [mounted, setMounted] = useState(false);

const homeRef = useRef<HTMLElement>(null);
Expand All @@ -16,20 +15,34 @@ const HeroSection = memo(() => {
// Intersection observer animation on scroll
useEffect(() => {
setMounted(true);
const getScreenWidth = () =>
const screenWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;

const currentHomeRef = homeRef.current;
// Scroll Animation
// ⚡ Optimization: Use direct DOM manipulation to toggle animation classes
// to avoid re-renders of the hero section on scroll.
if (currentHomeRef) {
const homeObserver = new IntersectionObserver(
([homeEntry]) => {
setIsHome(homeEntry.isIntersecting);
([entry]) => {
if (profileRef.current && introRef.current) {
if (entry.isIntersecting) {
profileRef.current.style.transform = "translateX(0)";
profileRef.current.style.opacity = "1";
introRef.current.style.transform = "translateX(0)";
introRef.current.style.opacity = "1";
} else {
profileRef.current.style.transform = "translateX(-500px)";
profileRef.current.style.opacity = "0";
introRef.current.style.transform = "translateX(500px)";
introRef.current.style.opacity = "0";
}
}
},
{
rootMargin: `${getScreenWidth() <= 700 ? "-100px" : "-300px"}`,
rootMargin: screenWidth <= 700 ? "-100px" : "-300px",
},
);

Expand All @@ -45,7 +58,7 @@ const HeroSection = memo(() => {
<section id="home" ref={homeRef} className="w-full">
<div className="min-h-[100vh] w-full overflow-x-hidden px-[20px] md:px-[50px] lg:px-[100px] xl:px-[200px] 2xl:px-[400px] flex flex-col md:flex-row content-center items-center justify-between shadow-zinc-300 dark:shadow-zinc-700 shadow-sm">
<div
className={`${isHome ? "translate-x-0 opacity-100" : "translate-x-[-500px] opacity-0"} transition-all duration-700 w-[300px] h-[300px] md:w-[400px] md:h-[400px] relative m-auto md:m-0 mt-[40px] md:mt-0 order-last md:order-last`}
className="transition-all duration-700 w-[300px] h-[300px] md:w-[400px] md:h-[400px] relative m-auto md:m-0 mt-[40px] md:mt-0 order-last md:order-last opacity-0 translate-x-[-500px]"
ref={profileRef}
>
<Image
Expand All @@ -59,7 +72,7 @@ const HeroSection = memo(() => {
</div>

<div
className={`${isHome ? "translate-x-0 opacity-100" : "translate-x-[500px] opacity-0"} transition-all duration-700 order-first md:order-first`}
className="transition-all duration-700 order-first md:order-first opacity-0 translate-x-[500px]"
ref={introRef}
>
<p className="text-2xl md:text-4xl py-2 font-sans text-center text-nowrap">
Expand Down