Skip to content

Commit

Permalink
Merge pull request #3 from thebaodev/component-type-tester
Browse files Browse the repository at this point in the history
feat: add TypeTester
  • Loading branch information
thebaodev committed Nov 8, 2022
2 parents 1eb88ed + fb92d7e commit d0c5294
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 109 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ node_modules
.vercel
.output
.vscode
.idea

/build/
/public/build
Expand Down
66 changes: 44 additions & 22 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 0 additions & 21 deletions app/components/Card.tsx

This file was deleted.

114 changes: 114 additions & 0 deletions app/components/TypeTester.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React, { forwardRef, useCallback, useEffect, useState } from 'react';

type TypeTesterProps = {
words?: string[];
};

const defaultWords = ['hello', 'world', 'this', 'is', 'a', 'test'];
const TypeTester = forwardRef<HTMLDivElement, TypeTesterProps>(
({ words = defaultWords }: TypeTesterProps, ref) => {
const [activeWord, setActiveWord] = useState(words[0]);
const [typed, setTyped] = useState('');
const [history, setHistory] = useState<string[]>([]);

const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
e.preventDefault();
if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) return;
switch (e.code) {
case 'Tab':
break;
case 'Space':
const nextWordIndex = words.indexOf(activeWord) + 1;
setActiveWord(words[nextWordIndex] || '');
setTyped('');
setHistory([...history, typed]);
break;
case 'Backspace':
if (typed.length === 0) {
const prevWordIndex = words.indexOf(activeWord) - 1;
setActiveWord(words[prevWordIndex] || '');
setTyped(history[prevWordIndex] || '');
setHistory(history.splice(0, history.length - 1));
return;
}
const newValue = typed.slice(0, -1);
setTyped(newValue);
break;
default:
setTyped(typed + e.key);
}
},
[activeWord, history, typed, words],
);

const attachEventListeners = useCallback(() => {
document.addEventListener('keydown', handleKeyDown);
}, [handleKeyDown]);

const removeEventListeners = useCallback(() => {
document.removeEventListener('keydown', handleKeyDown);
}, [handleKeyDown]);

useEffect(() => {
attachEventListeners();
return () => {
removeEventListeners();
};
}, [attachEventListeners, removeEventListeners]);

console.log({ typed });
const extraChars = typed.slice(activeWord.length);
return (
<div ref={ref}>
<div className="text-4xl flex flex-wrap gap-2">
{words.map((word, wordIndex) => {
const isTypedWord = history[wordIndex];
const isActive = word === activeWord;
console.log({ isTypedWord, isActive });
return (
<span key={word + wordIndex}>
{word.split('').map((char, charIndex) => {
const isTypedChar =
isTypedWord || (isActive && typed[charIndex]);
let isCorrect = false;
if (isTypedWord) {
isCorrect = history[wordIndex][charIndex] === char;
} else if (isTypedChar) {
isCorrect = typed[charIndex] === char;
}
return (
<span
className={
!isTypedChar
? 'text-gray-500'
: isCorrect
? 'text-green-500'
: 'text-red-500'
}
key={char + charIndex}
>
{char}
</span>
);
})}
<span>
{isActive &&
extraChars &&
extraChars.split('').map((char, charIndex) => (
<span className="text-red-500" key={char + charIndex}>
{char}
</span>
))}
</span>
</span>
);
})}
</div>
</div>
);
},
);

TypeTester.displayName = 'TypeTester';
export default TypeTester;
3 changes: 3 additions & 0 deletions app/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TypeTester from './TypeTester';

export { TypeTester };
24 changes: 0 additions & 24 deletions app/data/books.ts

This file was deleted.

19 changes: 19 additions & 0 deletions app/hooks/useInterval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useCallback, useEffect, useRef } from 'react';

export const useInterval = (callback: Function, delay: number | null) => {
const callbackRef = useRef(callback);

const tick = useCallback(() => {
callbackRef.current();
}, []);

useEffect(() => {
callbackRef.current = callback;
}, [callback]);

useEffect(() => {
if (!delay) return;
const id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay, tick]);
};
36 changes: 0 additions & 36 deletions app/routes/books.tsx

This file was deleted.

16 changes: 13 additions & 3 deletions app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { TypeTester } from '~/components';

const Index = () => (
<div className="flex justify-start items-center pt-20 h-screen w-screen flex-col text-center">
<h1>typesth</h1>
</div>
<main className="flex justify-center items-center h-screen w-screen flex-col text-center">
<header>
<h1>typesth</h1>
</header>
<div className="container flex-1 flex justify-center items-center">
<section>
<TypeTester />
</section>
</div>
<footer>made with love by bao</footer>
</main>
);

export default Index;
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"test:coverage": "vitest run --coverage",
"format:write": "prettier --write .",
"prepare": "husky install",
"semantic-release": "semantic-release"
},
"semantic-release": "semantic-release"
},
"eslintIgnore": [
"/node_modules",
"/build",
Expand All @@ -33,10 +33,13 @@
"remix.config.js"
],
"dependencies": {
"@headlessui/react": "^1.7.4",
"@heroicons/react": "^2.0.13",
"@remix-run/node": "^1.7.4",
"@remix-run/react": "^1.7.4",
"@remix-run/vercel": "^1.7.4",
"@vercel/node": "^2.5.10",
"hotkeys-js": "^3.10.0",
"isbot": "^3.6.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
6 changes: 5 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
module.exports = {
content: ['./app/**/*.{ts,tsx,jsx,js}'],
theme: {
extend: {},
extend: {
fontFamily: {
sans: ['SpaceGrotesk', 'serif'],
},
},
},
plugins: [],
};

0 comments on commit d0c5294

Please sign in to comment.