6 Commits

Author SHA1 Message Date
259c8237df Bob AI: Add an 'explode on click' animation effect to buttons in the 2026-02-24 10:09:49 +00:00
ba0ef17de6 Merge version_1 into main
Merge version_1 into main
2026-02-24 10:02:07 +00:00
2a23fc6ce0 Merge version_1 into main
Merge version_1 into main
2026-02-24 10:01:38 +00:00
2b0ccb58a8 Merge version_1 into main
Merge version_1 into main
2026-02-24 10:01:02 +00:00
64acf68c5c Merge version_1 into main
Merge version_1 into main
2026-02-24 10:00:39 +00:00
bf17921c90 Merge version_1 into main
Merge version_1 into main
2026-02-23 11:59:57 +00:00

View File

@@ -100,7 +100,7 @@ const HeroBillboard = ({
buttonClassName = "",
buttonTextClassName = "",
mediaWrapperClassName = "",
imageClassName = "",
imageClassName = "",
marqueeClassName = "",
marqueeItemClassName = "",
marqueeCardClassName = "",
@@ -110,6 +110,76 @@ const HeroBillboard = ({
}: HeroBillboardProps) => {
const { containerRef: mediaContainerRef } = useButtonAnimation({ animationType: mediaAnimation });
const handleButtonClick = (e: React.MouseEvent<HTMLButtonElement>, callback?: () => void) => {
const button = e.currentTarget;
const rect = button.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
// Create particle explosion effect
for (let i = 0; i < 12; i++) {
const particle = document.createElement("div");
const angle = (i / 12) * Math.PI * 2;
const velocity = 5 + Math.random() * 5;
const vx = Math.cos(angle) * velocity;
const vy = Math.sin(angle) * velocity;
particle.style.position = "fixed";
particle.style.left = x + "px";
particle.style.top = y + "px";
particle.style.width = "8px";
particle.style.height = "8px";
particle.style.borderRadius = "50%";
particle.style.backgroundColor = getComputedStyle(button).backgroundColor || "#3b82f6";
particle.style.pointerEvents = "none";
particle.style.zIndex = "9999";
particle.style.boxShadow = "0 0 10px currentColor";
document.body.appendChild(particle);
let px = x;
let py = y;
let pvx = vx;
let pvy = vy;
const gravity = 0.2;
const friction = 0.98;
let life = 1;
const animate = () => {
pvx *= friction;
pvy *= friction;
pvy += gravity;
px += pvx;
py += pvy;
life -= 0.02;
particle.style.left = px + "px";
particle.style.top = py + "px";
particle.style.opacity = String(Math.max(0, life));
if (life > 0) {
requestAnimationFrame(animate);
} else {
particle.remove();
}
};
animate();
}
// Execute button action after animation starts
if (callback) {
setTimeout(callback, 100);
}
};
const enhancedButtons = buttons?.map((button) => ({
...button,
onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
handleButtonClick(e, button.onClick as (() => void) | undefined);
},
}));
return (
<section
aria-label={ariaLabel}
@@ -123,7 +193,7 @@ const HeroBillboard = ({
tag={tag}
tagIcon={tagIcon}
tagAnimation={tagAnimation}
buttons={buttons}
buttons={enhancedButtons}
buttonAnimation={buttonAnimation}
avatars={avatars}
avatarText={avatarText}