diff --git a/src/App.js b/src/App.js
index af132d3..a76de12 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,172 +1,33 @@
-import React, { useEffect, useState } from 'react';
+import React, {useContext, useEffect} from 'react';
import './css/App.css';
-import MorseDisplay from './components/MorseDisplay'
-import MorseBufferDisplay from './components/MorseBufferDisplay'
import MorseButton from './components/MorseButton'
import ModePicker from './components/ModePicker'
-// import LettersDisplay from './components/LettersDisplay'
+// import MorseDisplay from './components/MorseDisplay'
+// import MorseBufferDisplay from './components/MorseBufferDisplay'
+// import GameClock from "./components/GameClock"
+// import ChallengeWord from "./components/ChallengeWord"
+import {GameModeContext} from "./gameContext"
+import PracticeMode from './app-modes/PracticeMode';
+import TimedMode from './app-modes/TimedMode'
+import ChallengeMode from './app-modes/ChallengeMode'
function App() {
- const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..'
- const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']]
-
- let charTimer = 0
- let charTime = 0
- let gapTimer = 0
- let gapTime = 0
-
- const timingUnit = 15 // default: 25
-
- const ditMaxTime = 5 // default: 3
- const letterGapMinTime = ditMaxTime*3
- const wordGapMaxTime = ditMaxTime*7
- const morseHistorySize = 5
-
- // Tone Setup
- let AudioContext = window.AudioContext || window.webkitAudioContext || false
- let context
- window.AudioContext = window.AudioContext || window.webkitAudioContext;
- if (AudioContext) {
- context = new AudioContext()
- } else {
- context = null
- }
-
- let o
- let frequency = 550.0
-
-
- function handleInputStart(event) {
- event.preventDefault()
- if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
- (event.repeat)) {
- return
- }
- if (context.state === 'interrupted') {
- context.resume()
- }
-
- o = context.createOscillator()
- o.frequency.value = frequency
- o.type = "sine"
-
- let g = context.createGain()
- g.gain.exponentialRampToValueAtTime(0.08, context.currentTime)
- o.connect(g)
- g.connect(context.destination)
- o.start()
-
- // if (gapTimer===0) { setMorseLettersBuffer('') }
- checkGapBetweenInputs()
- clearInterval(gapTimer)
-
-
- startCharTimer()
- }
- function startCharTimer() {
- // Reset character time
- charTime = 0
- // Start Character Timer
- charTimer = setInterval(() => {
- charTime += 1
- }, timingUnit);
- }
-
- function handleInputEnd(event) {
- event.preventDefault()
- if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
- (event.repeat)) {
- return
- }
-
- if (charTime <= ditMaxTime) {
- setMorseCharBuffer(prev => prev + '.')
- } else {
- setMorseCharBuffer(prev => prev + '-')
- }
-
- stopCharTimer()
- startGapTimer()
- o.stop()
- }
-
- function stopCharTimer() {
- clearInterval(charTimer)
- charTimer = 0
- }
-
- function startGapTimer() {
- gapTime = 0
- gapTimer = setInterval(() => {
- gapTime += 1
-
- // Gap between words
- if (gapTime >= wordGapMaxTime) {
- setMorseCharBuffer(prev => prev + '/')
- clearInterval(gapTimer)
- gapTimer = 0
- gapTime = 0
- }
- }, timingUnit);
- }
-
- function checkGapBetweenInputs() {
- // Check Gap between letters
- if ((gapTime >= letterGapMinTime) && (gapTime < wordGapMaxTime)) {
- // setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
- setMorseCharBuffer(prev => prev + ' ')
- // morseLettersBuffer = [...morseLettersBuffer, morseCharBuffer]
- // setMorseCharBuffer('')
-
- clearInterval(gapTimer)
- gapTimer = 0
- }
- }
-
- useEffect(() => {
- document.addEventListener('keydown', handleInputStart)
- document.addEventListener('keyup', handleInputEnd)
- document.getElementById('morseButton').addEventListener('mousedown', handleInputStart)
- document.getElementById('morseButton').addEventListener('touchstart', handleInputStart)
- document.getElementById('morseButton').addEventListener('mouseup', handleInputEnd)
- document.getElementById('morseButton').addEventListener('touchend', handleInputEnd)
- // eslint-disable-next-line
- }, [])
-
- useEffect(() => {
- if (morseCharBuffer.slice(-1) === ' ') {
- // setMorseLettersBuffer([morseCharBuffer])
- // setMorseCharBuffer('')
- }
- if (morseCharBuffer.slice(-1) === '/') {
- // Remove forward slash
- let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
- console.log('val: ', val);
-
- setMorseWords(prev => [val, ...prev])
-
- if (morseWords.length >= morseHistorySize) {
- setMorseWords(prev => prev.slice(0,prev.length-1))
- }
-
- setMorseCharBuffer('')
- }
-
- // setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
- // eslint-disable-next-line
- }, [morseCharBuffer])
console.log('App.js rendered')
+ const {gameMode} = useContext(GameModeContext)
return (
-
- Practice
+
+
+
+
-
- Timed Mode
-
-
- Challenge Mode
-
-
)
}
diff --git a/src/components/MorseButton.js b/src/components/MorseButton.js
index 66aaadd..1cba5f6 100644
--- a/src/components/MorseButton.js
+++ b/src/components/MorseButton.js
@@ -7,4 +7,4 @@ function MorseButton() {
)
}
-export default MorseButton
\ No newline at end of file
+export default React.memo(MorseButton)
\ No newline at end of file
diff --git a/src/css/App.css b/src/css/App.css
index 4e2edcc..9bcbe52 100644
--- a/src/css/App.css
+++ b/src/css/App.css
@@ -26,15 +26,18 @@ html, body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
+ -ms-flex-item-align: center;
+ align-self: center;
}
-#mode-picker div {
+#mode-picker button {
background: #fcfcfc;
margin: 15px;
padding: 5px;
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
- border-radius: 5px;
+ border: 0px;
+ border-radius: 0px;
}
#main-content {
@@ -60,6 +63,33 @@ html, body {
align-self: center;
}
+#challengeWord {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ height: 50px;
+ margin-bottom: 20px;
+ padding-left: 10px;
+ padding-right: 10px;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+ display: flex;
+ font-size: 40px;
+ font-family: 'Courier';
+ font-weight: bold;
+ background: #EEE;
+ text-transform: uppercase;
+ -ms-flex-item-align: center;
+ align-self: center;
+}
+
#morseBufferDisplay {
display: -webkit-box;
display: -ms-flexbox;
@@ -93,7 +123,7 @@ html, body {
height: 40px;
width: 30px !important;
margin-left: 3px;
- border-radius: 5px;
+ border-radius: 0px;
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
display: -webkit-box;
@@ -197,7 +227,7 @@ html, body {
margin: 3px;
background: #EEE;
white-space: nowrap;
- border-radius: 5px;
+ border-radius: 0px;
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
line-height: 2rem;
diff --git a/src/css/App.css.map b/src/css/App.css.map
index d2d75c2..a4c3262 100644
--- a/src/css/App.css.map
+++ b/src/css/App.css.map
@@ -1,6 +1,6 @@
{
"version": 3,
- "mappings": "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",
+ "mappings": "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",
"sources": [
"../scss/App.scss"
],
diff --git a/src/gameContext.js b/src/gameContext.js
new file mode 100644
index 0000000..890527e
--- /dev/null
+++ b/src/gameContext.js
@@ -0,0 +1,23 @@
+import React, {Component} from "react"
+const GameModeContext = React.createContext()
+
+class GameModeContextProvider extends Component {
+ state = {
+ gameMode: "practice"
+ }
+
+ switchGameModeTo = (mode = "practice") => {
+ this.setState({gameMode: mode})
+ }
+
+ render() {
+ return (
+
+ {this.props.children}
+
+ )
+ }
+
+}
+
+export {GameModeContextProvider, GameModeContext}
diff --git a/src/hooks/usePracticeMode.js b/src/hooks/usePracticeMode.js
new file mode 100644
index 0000000..2c3d965
--- /dev/null
+++ b/src/hooks/usePracticeMode.js
@@ -0,0 +1,30 @@
+import {useEffect} from "react"
+import useTelegraph from './hooks/useTelegraph'
+
+
+function usePracticeMode() {
+ const {morseCharBuffer, setMorseWords, morseWords, setMorseCharBuffer} = useTelegraph()
+
+ const morseHistorySize = 5
+
+ useEffect(() => {
+ if (morseCharBuffer.slice(-1) === '/') {
+ // Remove forward slash
+ let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
+ console.log('val: ', val);
+
+ setMorseWords(prev => [val, ...prev])
+
+ if (morseWords.length >= morseHistorySize) {
+ setMorseWords(prev => prev.slice(0,prev.length-1))
+ }
+
+ setMorseCharBuffer('')
+ }
+
+ // setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
+ // eslint-disable-next-line
+ }, [morseCharBuffer])
+}
+
+export default usePracticeMode
\ No newline at end of file
diff --git a/src/hooks/useTelegraph.js b/src/hooks/useTelegraph.js
new file mode 100644
index 0000000..d56fae7
--- /dev/null
+++ b/src/hooks/useTelegraph.js
@@ -0,0 +1,157 @@
+import {useState, useEffect} from 'react'
+
+function useTelegraph(mode = 'practice') {
+
+ const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..'
+ const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']]
+
+ let charTimer = 0
+ let charTime = 0
+ let gapTimer = 0
+ let gapTime = 0
+
+ const timingUnit = 15 // default: 25
+
+ const ditMaxTime = 5 // default: 3
+ const letterGapMinTime = ditMaxTime*3
+ const wordGapMaxTime = ditMaxTime*7
+ const morseHistorySize = 5
+
+ // Tone Setup
+ let AudioContext = window.AudioContext || window.webkitAudioContext || false
+ let context
+ window.AudioContext = window.AudioContext || window.webkitAudioContext;
+ if (AudioContext) {
+ context = new AudioContext()
+ } else {
+ context = null
+ }
+
+ let o
+ let frequency = 550.0
+
+ function clearHistory() {
+ setMorseWords([])
+ }
+
+ function handleInputStart(event) {
+
+ event.preventDefault()
+ if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
+ (event.repeat)) {
+ return
+ }
+ if (context.state === 'interrupted') {
+ context.resume()
+ }
+
+ o = context.createOscillator()
+ o.frequency.value = frequency
+ o.type = "sine"
+
+ let g = context.createGain()
+ g.gain.exponentialRampToValueAtTime(0.08, context.currentTime)
+ o.connect(g)
+ g.connect(context.destination)
+ o.start()
+
+ checkGapBetweenInputs()
+ clearInterval(gapTimer)
+
+ startCharTimer()
+ }
+ function startCharTimer() {
+ // Reset character time
+ charTime = 0
+ // Start Character Timer
+ charTimer = setInterval(() => {
+ charTime += 1
+ }, timingUnit);
+ }
+
+ function handleInputEnd(event) {
+ event.preventDefault()
+ if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
+ (event.repeat)) {
+ return
+ }
+
+ if (charTime <= ditMaxTime) {
+ setMorseCharBuffer(prev => prev + '.')
+ } else {
+ setMorseCharBuffer(prev => prev + '-')
+ }
+
+ stopCharTimer()
+ startGapTimer()
+ o.stop()
+ }
+
+ function stopCharTimer() {
+ clearInterval(charTimer)
+ charTimer = 0
+ }
+
+ function startGapTimer() {
+ gapTime = 0
+ gapTimer = setInterval(() => {
+ gapTime += 1
+
+ // Gap between words
+ if (gapTime >= wordGapMaxTime && mode === 'practice') {
+ setMorseCharBuffer(prev => prev + '/')
+ clearInterval(gapTimer)
+ gapTimer = 0
+ gapTime = 0
+ }
+ }, timingUnit);
+ }
+
+ function checkGapBetweenInputs() {
+ // Check Gap between letters
+ if ((gapTime >= letterGapMinTime) && (gapTime < wordGapMaxTime)) {
+ setMorseCharBuffer(prev => prev + ' ')
+ clearInterval(gapTimer)
+ gapTimer = 0
+ }
+ }
+
+ useEffect(() => {
+ document.addEventListener('keydown', handleInputStart)
+ document.addEventListener('keyup', handleInputEnd)
+
+ const morseButton = document.getElementById('morseButton')
+ morseButton.addEventListener('mousedown', handleInputStart)
+ morseButton.addEventListener('touchstart', handleInputStart)
+ morseButton.addEventListener('mouseup', handleInputEnd)
+ morseButton.addEventListener('touchend', handleInputEnd)
+
+ return function cleanup() {
+ document.removeEventListener('keydown', handleInputStart)
+ document.removeEventListener('keyup', handleInputEnd)
+ }
+ // eslint-disable-next-line
+ }, [])
+
+ useEffect(() => {
+ if (morseCharBuffer.slice(-1) === '/') {
+ // Remove forward slash
+ let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
+ console.log('val: ', val);
+
+ setMorseWords(prev => [val, ...prev])
+
+ if (morseWords.length >= morseHistorySize) {
+ setMorseWords(prev => prev.slice(0,prev.length-1))
+ }
+
+ setMorseCharBuffer('')
+ }
+
+ // eslint-disable-next-line
+ }, [morseCharBuffer])
+
+ return {morseCharBuffer, morseWords, clearHistory, setMorseCharBuffer, setMorseWords}
+}
+
+export default useTelegraph
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 87d1be5..959578c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,8 +3,13 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
+import {GameModeContextProvider} from "./gameContext"
-ReactDOM.render(
, document.getElementById('root'));
+ReactDOM.render(
+
+
+
+ , document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
diff --git a/src/scss/App.scss b/src/scss/App.scss
index 8590253..acf4f19 100644
--- a/src/scss/App.scss
+++ b/src/scss/App.scss
@@ -1,6 +1,6 @@
$main-bg-color: #FFF;
$main-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2);
-$main-border-radius: 5px;
+$main-border-radius: 0px;
// $border-radius-neumorphic: 0px -6px 10px rgba(255, 255, 255, 1), 0px 4px 15px rgba(0, 0, 0, 0.15);
html, body {
@@ -20,11 +20,13 @@ html, body {
}
#mode-picker {
display: flex;
- div {
+ align-self: center;
+ button {
background: #fcfcfc;
margin: 15px;
padding: 5px;
box-shadow: $main-box-shadow;
+ border: 0px;
border-radius: $main-border-radius;
}
}
@@ -43,7 +45,24 @@ html, body {
border-radius: 50%;
align-self: center;
}
-
+#challengeWord {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ // border: 1px solid green;
+ height: 50px;
+ margin-bottom: 20px;
+ padding-left: 10px;
+ padding-right: 10px;
+ width: fit-content;
+ display: flex;
+ font-size: 40px;
+ font-family: 'Courier';
+ font-weight: bold;
+ background: #EEE;
+ text-transform: uppercase;
+ align-self: center;
+}
#morseBufferDisplay {
display: flex;
justify-content: center;