Migrate to TS with ESLint and Prettier

This commit is contained in:
2025-01-28 22:54:38 +01:00
parent 40954e1f52
commit c17f0f484a
18 changed files with 1274 additions and 586 deletions
+112
View File
@@ -0,0 +1,112 @@
import { useEffect, useState } from 'react';
import { KEYS_TO_DISABLE } from 'constants/default';
import './index.css';
function Code() {
// TODO: Cleanup the file and create utils for trimming the code properly.
// TODO: Create a function that combines a sequence of spaces into tabs.
const [code, setCode] = useState<string>('');
const [loaded, setLoaded] = useState<boolean>(false);
const [characters, setCharacters] = useState<Array<boolean>>([]);
useEffect(() => {
(async function () {
setCode('');
const response = await fetch(
`${import.meta.env.VITE_API_URL}/generate?lang=lisp`,
);
if (!response.ok || !response.body) return;
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) {
break;
}
}
setCode((prev) => prev.trim());
setLoaded(true);
})();
}, []);
useEffect(() => {
function handleKeyPress(event: KeyboardEvent) {
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: number) {
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: string) {
if (/^\n$/.test(char)) return '\n';
if (/^(\s|\t)$/.test(char)) return '\u00A0';
return char;
}
function renderClassName(index: number) {
return `${renderCharacterClassName(index)}`.trim();
}
function renderCharacter(char: string, index: number) {
const rendered = renderSpacingCharacter(char);
if (/^\n$/.test(rendered)) {
return (
<span className={renderClassName(index)} key={char + index}>
<br />
</span>
);
}
return (
<span className={renderClassName(index)} key={char + index}>
{rendered}
</span>
);
}
return (
<div className='container'>
{code.split('').map((char, index) => renderCharacter(char, index))}
</div>
);
}
export default Code;