mirror of
https://github.com/hazemKrimi/touch-programming.git
synced 2026-05-01 18:20:26 +00:00
Migrate to TS with ESLint and Prettier
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
.container {
|
||||
margin: auto;
|
||||
padding: 1rem;
|
||||
letter-spacing: 0.12rem;
|
||||
}
|
||||
|
||||
.pending {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: gray;
|
||||
animation: blink 0.75s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.correct {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.incorrect {
|
||||
color: red;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
border-left: 1px solid white;
|
||||
}
|
||||
|
||||
50% {
|
||||
border-left: 1px solid transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
border-left: 1px solid white;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user