feat: name scramble
Signed-off-by: Ameya Shenoy <shenoy.ameya@gmail.com>
This commit is contained in:
parent
bbc40ec297
commit
f12356ae66
2 changed files with 111 additions and 9 deletions
|
|
@ -1,16 +1,14 @@
|
|||
import * as React from "react";
|
||||
import TextScramble from "@/components/TextScramble";
|
||||
|
||||
export function NameComponent() {
|
||||
return (
|
||||
<div className="flex justify-center font-[family-name:var(--font-spacegrotesk-sans)] font-semibold text-fluid tracking-tighter">
|
||||
<p>
|
||||
<span className="selection:bg-red-500">Ameya </span>
|
||||
<span
|
||||
className={`text-red-500 selection:bg-black dark:selection:bg-white`}
|
||||
>
|
||||
Shenoy
|
||||
</span>
|
||||
</p>
|
||||
<TextScramble
|
||||
firstName="Ameya"
|
||||
lastName="Shenoy"
|
||||
onlineHandleFirstName="coding"
|
||||
onlineHandleLastName="coffee"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
104
frontend/src/components/TextScramble.tsx
Normal file
104
frontend/src/components/TextScramble.tsx
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
|
||||
interface TextScrambleProps {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
onlineHandleFirstName: string;
|
||||
onlineHandleLastName: string;
|
||||
}
|
||||
|
||||
const TextScramble: React.FC<TextScrambleProps> = ({
|
||||
firstName,
|
||||
lastName,
|
||||
onlineHandleFirstName,
|
||||
onlineHandleLastName,
|
||||
}) => {
|
||||
const [displayFirstName, setfirstNameText] = useState(firstName);
|
||||
const [displayLastNameText, setLastNameText] = useState(lastName);
|
||||
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
const chars = "!<>-_\\/[]{}—=+*^?#________";
|
||||
|
||||
const scramble = useCallback(
|
||||
(fromText: string, toText: string, setFunctiono) => {
|
||||
let counter = 0;
|
||||
const length = Math.max(fromText.length, toText.length);
|
||||
const queue = [];
|
||||
|
||||
// Pad texts with spaces if they have different lengths
|
||||
fromText = fromText.padEnd(length, " ");
|
||||
toText = toText.padEnd(length, " ");
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const fromChar = fromText[i];
|
||||
const toChar = toText[i];
|
||||
const start = Math.floor(Math.random() * 40);
|
||||
const end = start + Math.floor(Math.random() * 40);
|
||||
queue.push({ fromText: fromChar, toText: toChar, start, end });
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
let output = "";
|
||||
let complete = 0;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const { fromText, toText, start, end } = queue[i];
|
||||
const char =
|
||||
counter >= end
|
||||
? toText
|
||||
: counter >= start
|
||||
? chars[Math.floor(Math.random() * chars.length)]
|
||||
: fromText;
|
||||
|
||||
output += char;
|
||||
if (counter >= end) complete++;
|
||||
}
|
||||
|
||||
setFunctiono(output);
|
||||
if (complete < length) {
|
||||
requestAnimationFrame(update);
|
||||
counter++;
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(update);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isHovering) {
|
||||
scramble(firstName, onlineHandleFirstName, setfirstNameText);
|
||||
scramble(lastName, onlineHandleLastName, setLastNameText);
|
||||
} else {
|
||||
scramble(displayFirstName, firstName, setfirstNameText);
|
||||
scramble(displayLastNameText, lastName, setLastNameText);
|
||||
}
|
||||
}, [isHovering, scramble, firstName, lastName]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="group relative font-mono transition-all duration-300"
|
||||
onMouseEnter={() => setIsHovering(true)}
|
||||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<span className="inline-block group-hover:opacity-0 transition-opacity">
|
||||
<span className="selection:bg-red-500">{displayFirstName}</span>
|
||||
<span className="text-red-500 selection:bg-black dark:selection:bg-white">
|
||||
{displayLastNameText}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<span className="selection:bg-red-500">{displayFirstName}</span>
|
||||
<span className="text-red-500 selection:bg-black dark:selection:bg-white">
|
||||
{displayLastNameText}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextScramble;
|
||||
Loading…
Reference in a new issue