This commit is contained in:
rosetta
2026-01-30 05:01:05 +02:00
commit 83f38dc63f
327 changed files with 18725 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
import { Button, ButtonProps } from '@mantine/core';
import { forwardRef, useMemo, useEffect } from 'react';
type AnimatedButtonProps = ButtonProps & {
animated?: [string, string];
animationDurationMs?: number;
onClick?: () => void;
};
export const AnimatedButton = forwardRef<HTMLButtonElement, AnimatedButtonProps>(
({ animated, animationDurationMs = 2000, style, onClick, disabled, ...rest }, ref) => {
const animationName = useMemo(() => {
if (!animated) return undefined;
const safe = (s: string) => s.replace(/[^a-zA-Z0-9]/g, '');
return `abg_${safe(animated[0])}_${safe(animated[1])}`;
}, [animated]);
useEffect(() => {
if (!animated || !animationName) return;
const id = `__${animationName}`;
let styleEl = document.getElementById(id) as HTMLStyleElement | null;
if (!styleEl) {
styleEl = document.createElement('style');
styleEl.id = id;
document.head.appendChild(styleEl);
}
styleEl.textContent = `@keyframes ${animationName}{0%{background-position:-200% 0;}100%{background-position:200% 0;}}`;
}, [animated, animationName]);
return (
<Button
ref={ref}
{...rest}
onClick={onClick}
disabled={disabled}
style={
animated && animationName && !disabled
? {
background: animated[0],
backgroundImage: `linear-gradient(90deg, transparent, ${animated[1]}, transparent)`,
backgroundSize: '50% 100%',
backgroundRepeat: 'no-repeat',
animation: `${animationName} ${animationDurationMs}ms linear infinite`,
willChange: 'background-position',
position: 'relative',
overflow: 'hidden',
...style,
}
: style
}
/>
);
}
);