feat: Implement initial cinematic portfolio UI with animated components and page structure.

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-18 06:45:42 -03:00
1 parent 9d779390e5
commit 2ede7e98f9
18 files changed
+2107 -147

No files matched your search

@@ -0,0 +1,82 @@
"use client";
import { useRef, useState, type ReactNode } from "react";
import { motion } from "framer-motion";
interface MagneticButtonProps {
children: ReactNode;
className?: string;
href?: string;
onClick?: () => void;
strength?: number;
as?: "a" | "button";
target?: string;
rel?: string;
download?: boolean;
"data-cursor"?: string;
}
export default function MagneticButton({
children,
className = "",
href,
onClick,
strength = 0.3,
as = "button",
target,
rel,
download,
"data-cursor": dataCursor,
}: MagneticButtonProps) {
const ref = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouse = (e: React.MouseEvent) => {
const el = ref.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
setPosition({
x: (e.clientX - centerX) * strength,
y: (e.clientY - centerY) * strength,
});
};
const handleMouseLeave = () => {
setPosition({ x: 0, y: 0 });
};
const Tag = as === "a" ? motion.a : motion.button;
const linkProps = as === "a" ? { href, target, rel, download } : {};
return (
<div
ref={ref}
onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave}
className="inline-block"
>
<Tag
className={className}
onClick={onClick}
data-cursor={dataCursor}
animate={{
x: position.x,
y: position.y,
}}
transition={{
type: "spring",
stiffness: 350,
damping: 15,
mass: 0.5,
}}
{...linkProps}
>
{children}
</Tag>
</div>
);
}