feat: Initialize portfolio project with core pages, UI components, and configuration files.

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-07 10:27:04 -03:00
1 parent aa07d6faeb
commit 0523052864
38 files changed
+1165 -460

No files matched your search

+41 -27
View File
@@ -1,7 +1,7 @@
'use client';
import React, { useRef, useEffect, useCallback, useMemo } from 'react';
import { gsap } from 'gsap';
import { InertiaPlugin } from 'gsap/InertiaPlugin';
"use client";
import React, { useRef, useEffect, useCallback, useMemo } from "react";
import { gsap } from "gsap";
import { InertiaPlugin } from "gsap/InertiaPlugin";
gsap.registerPlugin(InertiaPlugin);
@@ -46,15 +46,15 @@ function hexToRgb(hex: string) {
return {
r: parseInt(m[1], 16),
g: parseInt(m[2], 16),
b: parseInt(m[3], 16)
b: parseInt(m[3], 16),
};
}
const DotGrid: React.FC<DotGridProps> = ({
dotSize = 16,
gap = 32,
baseColor = '#5227FF',
activeColor = '#5227FF',
baseColor = "#5227FF",
activeColor = "#5227FF",
proximity = 150,
speedTrigger = 100,
shockRadius = 250,
@@ -62,8 +62,8 @@ const DotGrid: React.FC<DotGridProps> = ({
maxSpeed = 5000,
resistance = 750,
returnDuration = 1.5,
className = '',
style
className = "",
style,
}) => {
const wrapperRef = useRef<HTMLDivElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
@@ -76,14 +76,14 @@ const DotGrid: React.FC<DotGridProps> = ({
speed: 0,
lastTime: 0,
lastX: 0,
lastY: 0
lastY: 0,
});
const baseRgb = useMemo(() => hexToRgb(baseColor), [baseColor]);
const activeRgb = useMemo(() => hexToRgb(activeColor), [activeColor]);
const circlePath = useMemo(() => {
if (typeof window === 'undefined' || !window.Path2D) return null;
if (typeof window === "undefined" || !window.Path2D) return null;
const p = new Path2D();
p.arc(0, 0, dotSize / 2, 0, Math.PI * 2);
@@ -102,7 +102,7 @@ const DotGrid: React.FC<DotGridProps> = ({
canvas.height = height * dpr;
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
const ctx = canvas.getContext('2d');
const ctx = canvas.getContext("2d");
if (ctx) ctx.scale(dpr, dpr);
const cols = Math.floor((width + gap) / (dotSize + gap));
@@ -138,7 +138,7 @@ const DotGrid: React.FC<DotGridProps> = ({
const draw = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
@@ -178,15 +178,15 @@ const DotGrid: React.FC<DotGridProps> = ({
useEffect(() => {
buildGrid();
let ro: ResizeObserver | null = null;
if ('ResizeObserver' in window) {
if ("ResizeObserver" in window) {
ro = new ResizeObserver(buildGrid);
wrapperRef.current && ro.observe(wrapperRef.current);
} else {
(window as Window).addEventListener('resize', buildGrid);
(window as Window).addEventListener("resize", buildGrid);
}
return () => {
if (ro) ro.disconnect();
else window.removeEventListener('resize', buildGrid);
else window.removeEventListener("resize", buildGrid);
};
}, [buildGrid]);
@@ -231,10 +231,10 @@ const DotGrid: React.FC<DotGridProps> = ({
xOffset: 0,
yOffset: 0,
duration: returnDuration,
ease: 'elastic.out(1,0.75)'
ease: "elastic.out(1,0.75)",
});
dot._inertiaApplied = false;
}
},
});
}
}
@@ -259,29 +259,43 @@ const DotGrid: React.FC<DotGridProps> = ({
xOffset: 0,
yOffset: 0,
duration: returnDuration,
ease: 'elastic.out(1,0.75)'
ease: "elastic.out(1,0.75)",
});
dot._inertiaApplied = false;
}
},
});
}
}
};
const throttledMove = throttle(onMove, 50);
window.addEventListener('mousemove', throttledMove, { passive: true });
window.addEventListener('click', onClick);
window.addEventListener("mousemove", throttledMove, { passive: true });
window.addEventListener("click", onClick);
return () => {
window.removeEventListener('mousemove', throttledMove);
window.removeEventListener('click', onClick);
window.removeEventListener("mousemove", throttledMove);
window.removeEventListener("click", onClick);
};
}, [maxSpeed, speedTrigger, proximity, resistance, returnDuration, shockRadius, shockStrength]);
}, [
maxSpeed,
speedTrigger,
proximity,
resistance,
returnDuration,
shockRadius,
shockStrength,
]);
return (
<section className={`p-4 flex items-center justify-center h-full w-full relative ${className}`} style={style}>
<section
className={`p-4 flex items-center justify-center h-full w-full relative ${className}`}
style={style}
>
<div ref={wrapperRef} className="w-full h-full relative">
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full pointer-events-none" />
<canvas
ref={canvasRef}
className="absolute inset-0 w-full h-full pointer-events-none"
/>
</div>
</section>
);