From 87044a747b47bd83249d61a45842c7f7b2eae56d Mon Sep 17 00:00:00 2001 From: soryu Date: Sun, 11 Jan 2026 05:52:14 +0000 Subject: Contract system --- .../frontend/src/components/JapaneseHoverText.tsx | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 makima/frontend/src/components/JapaneseHoverText.tsx (limited to 'makima/frontend/src/components/JapaneseHoverText.tsx') diff --git a/makima/frontend/src/components/JapaneseHoverText.tsx b/makima/frontend/src/components/JapaneseHoverText.tsx new file mode 100644 index 0000000..3e60ee2 --- /dev/null +++ b/makima/frontend/src/components/JapaneseHoverText.tsx @@ -0,0 +1,77 @@ +import { useState, useCallback, useRef } from "react"; + +const GLYPHS = "▒▓░█#@*+:-/[]{}<>_"; + +interface JapaneseHoverTextProps { + japanese: string; + english: string; + className?: string; +} + +/** + * Displays Japanese text, transitions to English on hover with scramble effect + */ +export function JapaneseHoverText({ + japanese, + english, + className = "", +}: JapaneseHoverTextProps) { + const [isHovered, setIsHovered] = useState(false); + const [displayText, setDisplayText] = useState(english); + const timerRef = useRef | null>(null); + const iterationRef = useRef(0); + + const scrambleToEnglish = useCallback(() => { + setIsHovered(true); + + // Clear any existing animation + if (timerRef.current) { + clearInterval(timerRef.current); + } + + iterationRef.current = 0; + + timerRef.current = setInterval(() => { + const text = english; + const iteration = iterationRef.current; + + const display = text + .split("") + .map((char, index) => { + if (index < iteration) return char; + return GLYPHS.charAt(Math.floor(Math.random() * GLYPHS.length)); + }) + .join(""); + + setDisplayText(display); + iterationRef.current += 1; + + if (iteration > text.length + 2) { + if (timerRef.current) { + clearInterval(timerRef.current); + timerRef.current = null; + } + setDisplayText(english); + } + }, 26); + }, [english]); + + const resetToJapanese = useCallback(() => { + if (timerRef.current) { + clearInterval(timerRef.current); + timerRef.current = null; + } + setIsHovered(false); + setDisplayText(english); + }, [english]); + + return ( + + {isHovered ? displayText : japanese} + + ); +} -- cgit v1.2.3