173 lines
6.3 KiB
TypeScript
173 lines
6.3 KiB
TypeScript
// @ts-nocheck
|
|
'use client';
|
|
import { useEffect, useRef, useState } from 'react';
|
|
import { cn } from '../../lib/utils';
|
|
|
|
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,
|
|
}: {
|
|
gradientBackgroundStart?: string;
|
|
gradientBackgroundEnd?: string;
|
|
firstColor?: string;
|
|
secondColor?: string;
|
|
thirdColor?: string;
|
|
fourthColor?: string;
|
|
fifthColor?: string;
|
|
pointerColor?: string;
|
|
size?: string;
|
|
blendingValue?: string;
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
interactive?: boolean;
|
|
containerClassName?: string;
|
|
}) => {
|
|
const interactiveRef = useRef<HTMLDivElement>(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: React.MouseEvent<HTMLDivElement>) => {
|
|
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(
|
|
'relative left-0 top-0 h-screen w-screen overflow-hidden 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]`,
|
|
`left-[calc(50%-var(--size)/2)] top-[calc(50%-var(--size)/2)] h-[var(--size)] w-[var(--size)] [mix-blend-mode:var(--blending-value)]`,
|
|
`[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]`,
|
|
`left-[calc(50%-var(--size)/2)] top-[calc(50%-var(--size)/2)] h-[var(--size)] w-[var(--size)] [mix-blend-mode:var(--blending-value)]`,
|
|
`[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]`,
|
|
`left-[calc(50%-var(--size)/2)] top-[calc(50%-var(--size)/2)] h-[var(--size)] w-[var(--size)] [mix-blend-mode:var(--blending-value)]`,
|
|
`[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]`,
|
|
`left-[calc(50%-var(--size)/2)] top-[calc(50%-var(--size)/2)] h-[var(--size)] w-[var(--size)] [mix-blend-mode:var(--blending-value)]`,
|
|
`[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]`,
|
|
`left-[calc(50%-var(--size)/2)] top-[calc(50%-var(--size)/2)] h-[var(--size)] w-[var(--size)] [mix-blend-mode:var(--blending-value)]`,
|
|
`[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]`,
|
|
`-left-1/2 -top-1/2 h-full w-full [mix-blend-mode:var(--blending-value)]`,
|
|
`opacity-70`,
|
|
)}
|
|
></div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|