Initial commit

This commit is contained in:
dk
2026-06-14 06:41:21 +00:00
commit 9bfb4397bc
315 changed files with 37990 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
import { useRive, Layout, Fit } from "@rive-app/react-canvas";
import { useTagEffects } from "./useTagEffects";
import { useRiveHoverInput } from "./useRiveHoverInput";
const STATE_MACHINE_NAME = "State Machine 1";
const HOVER_INPUT_NAME = "Hover";
export const Tag = () => {
const { shouldShow, handleMouseEnter, handleClick, buttonClassName } = useTagEffects();
const { rive, RiveComponent } = useRive({
src: "https://webuild-dev.s3.eu-north-1.amazonaws.com/default/watermark-bob2.riv",
stateMachines: STATE_MACHINE_NAME,
autoplay: true,
layout: new Layout({
fit: Fit.Contain,
}),
});
const setHover = useRiveHoverInput(rive, STATE_MACHINE_NAME, HOVER_INPUT_NAME);
const handleTagClick = () => {
window.open("https://webild.io", "_blank", "noopener,noreferrer");
};
const onMouseEnter = () => {
handleMouseEnter();
setHover(true);
};
const onMouseLeave = () => {
setHover(false);
};
if (!shouldShow) {
return null;
}
return (
<button
type="button"
aria-label="Webild tag"
className={`fixed z-[99999] bottom-6 right-6 w-[160px] h-[92px] cursor-pointer ${buttonClassName}`}
onClick={(e) => handleClick(e, handleTagClick)}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<RiveComponent className="w-full h-full" />
</button>
);
};
export default Tag;

View File

@@ -0,0 +1,30 @@
import { useCallback, useEffect, useRef } from "react";
import { useStateMachineInput } from "@rive-app/react-canvas";
export function useRiveHoverInput(
rive: unknown,
stateMachineName: string,
hoverInputName: string
) {
const hoverInput = useStateMachineInput(
rive as never,
stateMachineName,
hoverInputName
);
const hoverInputRef = useRef<typeof hoverInput | null>(null);
useEffect(() => {
hoverInputRef.current = hoverInput ?? null;
}, [hoverInput]);
return useCallback(
(isHovering: boolean) => {
const input = hoverInputRef.current;
if (!input) return;
input.value = isHovering;
},
[]
);
}

View File

@@ -0,0 +1,54 @@
import { useRef, useEffect, useCallback, useState } from "react";
export function useTagEffects<T extends HTMLElement = HTMLButtonElement>() {
const audioRef = useRef<HTMLAudioElement | null>(null);
const [shouldShow, setShouldShow] = useState(true);
useEffect(() => {
audioRef.current = new Audio("https://webuild-dev.s3.eu-north-1.amazonaws.com/default/audio/click.mp3");
audioRef.current.volume = 0.75;
}, []);
useEffect(() => {
if (window.self !== window.top) {
try {
const parentHostname = window.top?.location.hostname;
if (parentHostname?.includes('webild.io')) {
setShouldShow(false);
}
} catch {
setShouldShow(true);
}
}
}, []);
const playSound = useCallback(() => {
if (audioRef.current) {
audioRef.current.currentTime = 0;
audioRef.current.play().catch(() => {});
}
}, []);
const handleMouseEnter = useCallback(() => {
if (window.innerWidth > 768) {
playSound();
}
}, [playSound]);
const handleClick = useCallback(
(e: React.MouseEvent<T>, onClick?: (e: React.MouseEvent<T>) => void) => {
playSound();
if (onClick) {
onClick(e);
}
},
[playSound]
);
return {
shouldShow,
handleMouseEnter,
handleClick,
buttonClassName: "transition-all duration-200 hover:-translate-y-[3px]",
};
}