Initial commit

This commit is contained in:
dk
2026-02-09 18:15:04 +02:00
commit f968fac9d9
297 changed files with 57823 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
"use client";
import { memo } from "react";
import useMagneticEffect from "./useMagneticEffect";
import { useButtonClick } from "../useButtonClick";
import { cls } from "@/lib/utils";
interface ButtonHoverMagneticProps {
text: string;
onClick?: () => void;
href?: string;
className?: string;
textClassName?: string;
strengthFactor?: number;
disabled?: boolean;
ariaLabel?: string;
type?: "button" | "submit" | "reset";
scrollToSection?: boolean;
}
const ButtonHoverMagnetic = ({
text,
onClick,
href,
className = "",
textClassName = "",
strengthFactor = 20,
disabled = false,
ariaLabel,
type = "button",
scrollToSection,
}: ButtonHoverMagneticProps) => {
const magneticRef = useMagneticEffect(strengthFactor);
const handleClick = useButtonClick(href, onClick, scrollToSection);
return (
<button
ref={magneticRef as React.RefObject<HTMLButtonElement>}
data-href={href}
type={type}
onClick={handleClick}
disabled={disabled}
aria-label={ariaLabel || text}
className={cls(
"relative cursor-pointer h-9 min-w-0 w-fit max-w-full px-6 primary-button rounded-theme text-background",
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
>
<span className={cls("text-sm block overflow-hidden truncate whitespace-nowrap", textClassName)}>{text}</span>
</button>
);
};
ButtonHoverMagnetic.displayName = "ButtonHoverMagnetic";
export default memo(ButtonHoverMagnetic);

View File

@@ -0,0 +1,73 @@
"use client";
import { useEffect, useRef } from "react";
const useMagneticEffect = (strengthFactor = 10) => {
const elementRef = useRef<HTMLElement | null>(null);
useEffect(() => {
if (typeof window === "undefined") return;
import("gsap").then((gsap) => {
const element = elementRef.current;
if (!element || window.innerWidth < 768) return;
const resetEl = (el: HTMLElement, immediate: boolean) => {
if (!el) return;
gsap.default.killTweensOf(el);
(immediate ? gsap.default.set : gsap.default.to)(el, {
x: "0vw",
y: "0vw",
rotate: "0deg",
clearProps: "all",
...(!immediate && { ease: "elastic.out(1, 0.3)", duration: 1.6 })
});
};
const resetOnEnter = () => {
resetEl(element, true);
};
const moveMagnet = (e: MouseEvent) => {
const b = element.getBoundingClientRect();
const strength = strengthFactor;
const offsetX = ((e.clientX - b.left) / element.offsetWidth - 0.5) * (strength / 16);
const offsetY = ((e.clientY - b.top) / element.offsetHeight - 0.5) * (strength / 16);
gsap.default.to(element, {
x: offsetX + "vw",
y: offsetY + "vw",
rotate: "0.001deg",
ease: "power4.out",
duration: 1.6
});
};
const resetMagnet = () => {
gsap.default.to(element, {
x: "0vw",
y: "0vw",
ease: "elastic.out(1, 0.3)",
duration: 1.6,
clearProps: "all"
});
};
element.addEventListener("mouseenter", resetOnEnter);
element.addEventListener("mousemove", moveMagnet);
element.addEventListener("mouseleave", resetMagnet);
return () => {
element.removeEventListener("mouseenter", resetOnEnter);
element.removeEventListener("mousemove", moveMagnet);
element.removeEventListener("mouseleave", resetMagnet);
};
});
}, [strengthFactor]);
return elementRef;
};
export default useMagneticEffect;