openoperator / components /shared /hero-flame.tsx
Leon4gr45's picture
Deploy to clean space
75fefa7 verified
"use client";
import { useEffect, useRef, useState } from "react";
import { cn } from "@/utils/cn";
// Sample of flame frames - using a subset for performance
const flameFrames = [
`
β–„β–„β–„
β–„β–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ
β–ˆ β–€ β–ˆβ–ˆ
`,
`
β–„β–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ
β–ˆ β–€ β–ˆβ–ˆ
`,
`
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–€β–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆβ–ˆβ–„β–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ
β–ˆβ–ˆ β–€β–€ β–ˆβ–ˆβ–ˆ
β–ˆ β–ˆβ–ˆ
`,
`
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆβ–€β–€β–€β–ˆβ–ˆβ–ˆβ–ˆ
β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ β–ˆβ–ˆβ–ˆ
β–ˆβ–ˆ β–€β–€ β–ˆβ–ˆ
β–ˆ β–ˆ
`,
];
interface HeroFlameProps {
className?: string;
size?: "small" | "medium" | "large";
}
export function HeroFlame({ className, size = "medium" }: HeroFlameProps) {
const [frameIndex, setFrameIndex] = useState(0);
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
intervalRef.current = setInterval(() => {
setFrameIndex((prev) => (prev + 1) % flameFrames.length);
}, 85);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, []);
const sizeClasses = {
small: "text-[8px] leading-[10px]",
medium: "text-[12px] leading-[14px]",
large: "text-[16px] leading-[18px]",
};
return (
<div
className={cn("flex gap-4 pointer-events-none select-none", className)}
>
{/* Left flame */}
<div className="relative overflow-hidden">
<pre
className={cn(
"text-heat-100 font-mono whitespace-pre",
sizeClasses[size],
)}
>
{flameFrames[frameIndex]}
</pre>
</div>
{/* Right flame (mirrored) */}
<div className="relative overflow-hidden -scale-x-100">
<pre
className={cn(
"text-heat-100 font-mono whitespace-pre",
sizeClasses[size],
)}
>
{flameFrames[frameIndex]}
</pre>
</div>
</div>
);
}