146 lines
5.7 KiB
JavaScript
146 lines
5.7 KiB
JavaScript
"use client";
|
|
import { cn } from "@/lib/utils";
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
export const BackgroundGradientAnimation = ({
|
|
gradientBackgroundStart = "rgb(108, 0, 162)",
|
|
gradientBackgroundEnd = "rgb(0, 17, 82)",
|
|
firstColor = "18, 113, 255",
|
|
secondColor = "221, 74, 255",
|
|
thirdColor = "100, 220, 255",
|
|
fourthColor = "200, 50, 50",
|
|
fifthColor = "180, 180, 50",
|
|
pointerColor = "140, 100, 255",
|
|
size = "80%",
|
|
blendingValue = "hard-light",
|
|
children,
|
|
className,
|
|
interactive = true,
|
|
containerClassName
|
|
}) => {
|
|
const interactiveRef = useRef(null);
|
|
|
|
const [curX, setCurX] = useState(0);
|
|
const [curY, setCurY] = useState(0);
|
|
const [tgX, setTgX] = useState(0);
|
|
const [tgY, setTgY] = useState(0);
|
|
useEffect(() => {
|
|
document.body.style.setProperty("--gradient-background-start", gradientBackgroundStart);
|
|
document.body.style.setProperty("--gradient-background-end", gradientBackgroundEnd);
|
|
document.body.style.setProperty("--first-color", firstColor);
|
|
document.body.style.setProperty("--second-color", secondColor);
|
|
document.body.style.setProperty("--third-color", thirdColor);
|
|
document.body.style.setProperty("--fourth-color", fourthColor);
|
|
document.body.style.setProperty("--fifth-color", fifthColor);
|
|
document.body.style.setProperty("--pointer-color", pointerColor);
|
|
document.body.style.setProperty("--size", size);
|
|
document.body.style.setProperty("--blending-value", blendingValue);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
function move() {
|
|
if (!interactiveRef.current) {
|
|
return;
|
|
}
|
|
setCurX(curX + (tgX - curX) / 20);
|
|
setCurY(curY + (tgY - curY) / 20);
|
|
interactiveRef.current.style.transform = `translate(${Math.round(curX)}px, ${Math.round(curY)}px)`;
|
|
}
|
|
|
|
move();
|
|
}, [tgX, tgY]);
|
|
|
|
const handleMouseMove = (event) => {
|
|
if (interactiveRef.current) {
|
|
const rect = interactiveRef.current.getBoundingClientRect();
|
|
setTgX(event.clientX - rect.left);
|
|
setTgY(event.clientY - rect.top);
|
|
}
|
|
};
|
|
|
|
const [isSafari, setIsSafari] = useState(false);
|
|
useEffect(() => {
|
|
setIsSafari(/^((?!chrome|android).)*safari/i.test(navigator.userAgent));
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"h-screen w-screen relative overflow-hidden top-0 left-0 bg-[linear-gradient(40deg,var(--gradient-background-start),var(--gradient-background-end))]",
|
|
containerClassName
|
|
)}>
|
|
<svg className="hidden">
|
|
<defs>
|
|
<filter id="blurMe">
|
|
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
|
|
<feColorMatrix
|
|
in="blur"
|
|
mode="matrix"
|
|
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -8"
|
|
result="goo" />
|
|
<feBlend in="SourceGraphic" in2="goo" />
|
|
</filter>
|
|
</defs>
|
|
</svg>
|
|
<div className={cn("", className)}>{children}</div>
|
|
<div
|
|
className={cn(
|
|
"gradients-container h-full w-full blur-lg",
|
|
isSafari ? "blur-2xl" : "[filter:url(#blurMe)_blur(40px)]"
|
|
)}>
|
|
<div
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_var(--first-color)_0,_var(--first-color)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-[var(--size)] h-[var(--size)] top-[calc(50%-var(--size)/2)] left-[calc(50%-var(--size)/2)]`,
|
|
`[transform-origin:center_center]`,
|
|
`animate-first`,
|
|
`opacity-100`
|
|
)}></div>
|
|
<div
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_rgba(var(--second-color),_0.8)_0,_rgba(var(--second-color),_0)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-[var(--size)] h-[var(--size)] top-[calc(50%-var(--size)/2)] left-[calc(50%-var(--size)/2)]`,
|
|
`[transform-origin:calc(50%-400px)]`,
|
|
`animate-second`,
|
|
`opacity-100`
|
|
)}></div>
|
|
<div
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_rgba(var(--third-color),_0.8)_0,_rgba(var(--third-color),_0)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-[var(--size)] h-[var(--size)] top-[calc(50%-var(--size)/2)] left-[calc(50%-var(--size)/2)]`,
|
|
`[transform-origin:calc(50%+400px)]`,
|
|
`animate-third`,
|
|
`opacity-100`
|
|
)}></div>
|
|
<div
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_rgba(var(--fourth-color),_0.8)_0,_rgba(var(--fourth-color),_0)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-[var(--size)] h-[var(--size)] top-[calc(50%-var(--size)/2)] left-[calc(50%-var(--size)/2)]`,
|
|
`[transform-origin:calc(50%-200px)]`,
|
|
`animate-fourth`,
|
|
`opacity-70`
|
|
)}></div>
|
|
<div
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_rgba(var(--fifth-color),_0.8)_0,_rgba(var(--fifth-color),_0)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-[var(--size)] h-[var(--size)] top-[calc(50%-var(--size)/2)] left-[calc(50%-var(--size)/2)]`,
|
|
`[transform-origin:calc(50%-800px)_calc(50%+800px)]`,
|
|
`animate-fifth`,
|
|
`opacity-100`
|
|
)}></div>
|
|
|
|
{interactive && (
|
|
<div
|
|
ref={interactiveRef}
|
|
onMouseMove={handleMouseMove}
|
|
className={cn(
|
|
`absolute [background:radial-gradient(circle_at_center,_rgba(var(--pointer-color),_0.8)_0,_rgba(var(--pointer-color),_0)_50%)_no-repeat]`,
|
|
`[mix-blend-mode:var(--blending-value)] w-full h-full -top-1/2 -left-1/2`,
|
|
`opacity-70`
|
|
)}></div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|