import { useEffect, useState } from 'react'; import './App.css'; const KEYS_TO_DISABLE = ['Backspace', 'Shift', 'Alt', 'Control', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'Escape', 'Delete', 'PageDown', 'PageUp', 'Home', 'End', 'Insert', 'WakeUp', 'Pause', 'ScrollLock', 'ContextMenu', 'BrowserForward', 'BrowserBack', 'CapsLock', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']; function App() { // TODO: Cleanup the file and create utils for spacing and trimming the code properly. const [code, setCode] = useState(''); const [loaded, setLoaded] = useState(false); const [characters, setCharacters] = useState([]); useEffect(() => { (async function() { setCode(''); const response = await fetch(`${import.meta.env.VITE_API_URL}/generate?lang=go&lines=10`); const reader = response.body.getReader(); const decoder = new TextDecoder(); while(true) { const {value, done} = await reader.read(); setCode(prev => prev + decoder.decode(value)); if (done) { setLoaded(true); setCode(prev => prev.trim()); break; } } })(); }, []); useEffect(() => { function handleKeyPress(event) { event.preventDefault(); if (!loaded) return; if (characters.length === code.length) return; if (KEYS_TO_DISABLE.includes(event.key)) return; const char = code[characters.length]; if (/^\n$/.test(char)) return setCharacters( characters.concat(event.key === 'Enter') ); if (/^(\s|\t)$/.test(char)) return setCharacters( characters.concat(['Space', 'Tab'].includes(event.key)) ); setCharacters( characters.concat(event.key === char) ); } window.addEventListener('keydown', handleKeyPress); return () => window.removeEventListener('keydown', handleKeyPress); // eslint-disable-next-line react-hooks/exhaustive-deps }, [loaded, characters]); function renderCharacterClassName(index) { const typed = characters[index]; if (loaded && index === characters.length) return 'highlight'; if (typeof typed === 'undefined') return 'pending'; if (!typed) return 'incorrect'; return 'correct'; } function renderSpacingCharacter(char) { if (/^\n$/.test(char)) return '\n'; if (/^(\s|\t)$/.test(char)) return '\u00A0' return char; } function renderClassName(index) { return `${renderCharacterClassName(index)}`.trim(); } function renderCharacter(char, index) { const rendered = renderSpacingCharacter(char); if (/^\n$/.test(rendered)) { return
} return ( {rendered} ); } return (
{code.split('').map((char, index) => renderCharacter(char, index))}
); } export default App;