Wordlist addition, file cleanup

This commit is contained in:
Gene Mecija 2020-02-11 00:44:57 -08:00
parent 91bca8c545
commit 1e25c16a3c
31 changed files with 92 additions and 612 deletions

View file

@ -23,6 +23,7 @@ import Footer from './components/Footer';
import ChallengeOverlay from './components/ChallengeOverlay';
import SidebarLeft from './components/SidebarLeft';
import FrequencyPicker from './components/FrequencyPicker';
import Tip from './components/Tip';
export default React.memo(function App() {
@ -57,16 +58,6 @@ export default React.memo(function App() {
{gameMode === 'practice' &&
<PracticeMode />
}
{/* {gameMode === 'timed' &&
<>
{keyType === "straight" ?
<StraightKey gameMode='training' /> : <ElectronicKey gameMode='training' />}
<TrainingMode /><br/>
<MorseBufferDisplay /><br/>
<MorseHistory /><br/>
</>
} */}
{gameMode === 'challenge' &&
<>
@ -76,7 +67,7 @@ export default React.memo(function App() {
}
<MorseButtons />
<span id='tip'>Tap the button to use the telegraph.</span>
<Tip />
</div>
{/* <div className="sidebar" id="right">
<div id="settings-icon" onClick={toggleRight}><i class="ri-settings-3-line"></i></div>

View file

@ -2,7 +2,6 @@ import React, { useContext } from 'react';
import '../css/App.css';
import MorseBufferDisplay from '../components/MorseBufferDisplay'
import MorseHistoryTextBox from '../components/MorseHistory_textbox'
import MorseHistory from '../components/MorseHistory'
import { KeyTypeContext } from '../contexts/keyTypeContext';
import StraightKey from '../components/StraightKey';
import ElectronicKey from '../components/ElectronicKey';

View file

@ -1,10 +1,8 @@
import React from "react"
// import DitDahDisplay from "./DitDahDisplay"
import morseCode from '../data/morse-reverse.json'
import ChallengeBufferDisplay from "./ChallengeBufferDisplay";
// import ChallengeWord from "./ChallengeWord";
function ChallengeDisplay(props) {
export default React.memo(function ChallengeDisplay(props) {
let morseLetters = props.buffer.split('_').filter(l => l !== '')
let challengeLetters = props.word.split('')
@ -17,46 +15,14 @@ function ChallengeDisplay(props) {
if (morseAlpha === challengeLetter) {
correctIndexes.push(index)
console.log('MATCH', correctIndexes);
} else {
if (props.buffer.slice(-1) === "_") {
incorrectIndex = index
console.log('MISMATCH:', incorrectIndex, 'should be', challengeLetter, 'instead of', morseAlpha, '>', morseLetter);
// props.setMorseCharBuffer(morseLetters.slice(0,-1).join('_') + '_')
}
}
// else {
// let onlyCorrectMorse = morseLetters.splice(0,index+1).join(' ')
// props.setMorseCharBuffer(onlyCorrectMorse)
// }
})
// for (let i in morseLetters) {
// let morseLetter = morseLetters[i].slice(-1) === '/' ?
// morseLetters[i].slice(0,morseLetters[i].length-1) : morseLetters[i]
// let challengeLetter = challengeLetters[i].toLowerCase()
// let endOfMorseLetter = morseLetter.includes('/')
// let morseAlpha = morseCode[morseLetter]
// if (challengeLetter === morseAlpha && endOfMorseLetter) {
// correctIndexes.push(i)
// console.log('CORRECT!!', `"${morseAlpha}"`);
// morseLetters[i] = morseLetters[i].slice(0,morseLetters[i].length-1)
// console.log(morseLetters);
// props.setMorseCharBuffer(morseLetters.join(' '))
// }
// else if (challengeLetter !== morseAlpha && endOfMorseLetter) {
// console.log('WRONG!!', `"${morseLetter}"`)
// // Rejoin morse characters except the last wrong character
// props.setMorseCharBuffer(morseLetters.slice(0,morseLetters.length-1).join(' '))
// }
// }
let spannedWord = challengeLetters.map((letter,index) => {
// console.log('correctIndexes',correctIndexes);
// console.log('index',index);
let className = 'cLetter'
className += (correctIndexes.includes(index)) ? ' correct' : ''
className += (incorrectIndex === index) ? ' morseError' : ''
@ -66,13 +32,10 @@ function ChallengeDisplay(props) {
})
return (
<>
<div id="challengeWord">{spannedWord}</div>
<ChallengeBufferDisplay buffer={props.buffer.slice(0,-1).replace(/_/g, ' ')} incorrectIndex={incorrectIndex} />
</>
)
}
export default React.memo(ChallengeDisplay)
})

View file

@ -1,6 +1,5 @@
import React, { useContext } from "react"
import { WordFeederContext } from "../contexts/wordFeederContext"
import { ChallengeContext } from "../contexts/challengeContext"
export default React.memo(function ChallengeWord(props) {

View file

@ -2,12 +2,9 @@ import React from "react"
export default (function Header () {
function handleClick(e) {
e.preventDefault()
}
return (
<div id="header">Learn Morse Code</div>
<div id="header">
Learn Morse Code
</div>
)
})

View file

@ -2,8 +2,6 @@ import React from "react"
import useMorsePlayer from "../hooks/useMorsePlayer"
import straight_key from "../images/straight_key.jpg"
import electronic_key from "../images/electronic_key.jpg"
import Legend from "./Legend"
import PlayMorseInput from "./PlayMorseInput"
export default React.memo(function Info() {
@ -12,33 +10,33 @@ export default React.memo(function Info() {
return (
<div id="info">
<h1>Morse Code</h1>
<p>Morse code is a method of communication via short and long tones with standard spacing between each tone.</p>
<p>Morse code is a method of communication that uses short and long tones. This tool will help you learn Morse Code.</p>
<h2>Dits and Dahs</h2>
<p>
<span className="bold">Dit</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('.')}></i> Denoted as a dot (.), dits are short tones and are base unit of morse code.<br />
<span className="bold">Dah</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('-')}></i> Denoted as a dash (-), dahs are long tones the length of three dits.
<span className="bold">Dit</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('.')}></i> Denoted as a period/dot (<span className="ditdah">.</span>), dits are short tones and are the base unit of Morse Code communication.<br />
<span className="bold">Dah</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('-')}></i> Denoted as a dash (<span className="ditdah">-</span>), dahs are long tones the length of three dits.
</p>
<h2>Spacing</h2 >
<p>
<span className="bold">Intra-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i> Silence between dits and dahs the length of one dit. Three dits separated by one-dit-long spaces is an "S".<br />
<span className="bold">Inter-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('. . .')}></i> Silence the length of three dits. Three dits separated by three-dit-long spaces is "EEE".<br />
<span className="bold">Inter-word Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('././.')}></i> Silence the length of seven dits. Three dits separated by seven-dit-long spaces is "E E E".
<p>The spacing between dits and dahs matters in Morse Code. Spacing of various lenghts signify different things.<br/>
<span className="bold">Intra-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i> Space between dits and dahs the length of one dit signify the dits and dahs are part of the same character. E.g. three dits separated by one-dit-long spaces is an "S".<br />
<span className="bold">Inter-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('. . .')}></i> Space the length of three dits signify a new letter. A single dit is an "E". Three dits, each separated by three-dit-long spaces, is "EEE".<br />
<span className="bold">Inter-word Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('././.')}></i> Space the length of seven dits signifies a new word. Three dits, each separated by seven-dit-long spaces, is "E E E".
</p>
<h2>Speed</h2>
<p>
Adjusting the <b>WPM</b> (Words Per Minute) in the Options Menu will adjust the lengths of the dits, dahs, and spacing accordingly.
The rate of communication is increased or decreased by adjusting the length of the dits, which in turn adjusts the length of dahs and spaces. Adjust the <b>WPM</b> (Words Per Minute) in the Options section to adjust the speed.
</p>
<h2>Telegraph Key Types</h2 >
<p>The instrument used to send morse code is called the key.</p>
<p>The instrument used to send Morse Code is called the key.</p>
<center><img src={straight_key} alt="Straight Key" /></center>
<p><b>Straight Keys</b> use a single button and generates tones when pressed down. Straight keys require greater accuracy as you control the dits, dahs, and spacing manually.</p>
<p><b>Straight Keys</b> use a single button and generate tones when pressed down. Straight keys require greater accuracy as the length of dits, dahs, and spacing is completely under manual control.</p>
<center><img src={electronic_key} alt="Electronic Key"></img></center>
<p><b>Electronic Keys</b> automatically generate dits or dahs of appropriate length. The Electronic Keyer used here is an Iambic keyer. It uses two paddles, one for dits, one for dahs. Switch between the two at the appropriate times to build letters.</p>
<p><b>Electronic Keys</b> use two paddles (one for dit, one for dah) that automatically generate the tones when pressed. The Electronic Keyer used here is an Iambic keyer, which alternates between dit and dah when both paddles are pressed. Switch between the two at the appropriate times to build letters in Morse Code.</p>
</div>
)
})

View file

@ -8,7 +8,6 @@ export default React.memo(function KeyTypePicker() {
function handleClick(e) {
setKeyType(e.target.id)
console.log("KEYTYPE PICKED:", e.target.id);
let buttons = document.querySelector(".mode-picker#keyType #buttons").childNodes
buttons.forEach(button => {
@ -34,13 +33,13 @@ export default React.memo(function KeyTypePicker() {
useEffect(() => {
document.querySelector(`button#${keyType}`).classList.add('selected')
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<div id="keyType" className="mode-picker">
<div id="title">
Key Type
{/* &nbsp;<i className="ri-question-line"></i> */}
</div>
<div id="buttons">
<button id="straight" onClick={handleClick}>
@ -52,26 +51,4 @@ export default React.memo(function KeyTypePicker() {
</div>
</div>
)
})
// > STRAIGHT KEY SELECTED
// CONTEXT LOAD: KeyTypeContextProvider
// COMPONENT LOADED: PracticeMode
// COMPONENT LOAD: MorseBufferDisplay
// COMPONENT LOAD: MorseDisplay
// morseWords Array []
// —————————
// > ELECTRONIC KEY SELECTED
// CONTEXT LOAD: KeyTypeContextProvider
// COMPONENT LOADED: PracticeMode
// COMPONENT LOAD: MorseBufferDisplay
// COMPONENT LOAD: MorseDisplay
// morseWords Array []
// CONTEXT LOAD: MorseBufferContextProvider // MorseBufferContextProvider reloading when Electronic selected
// COMPONENT LOAD: MorseBufferDisplay
// COMPONENT LOAD: MorseDisplay
// morseWords Array []
})

View file

@ -1,3 +1,4 @@
/* eslint-disable array-callback-return */
import React from "react"
import morseCode from '../data/morse-code.json'
import useMorsePlayer from "../hooks/useMorsePlayer";
@ -11,17 +12,13 @@ function Legend() {
let word = e.target.innerText
// let newWord = word
if (e.target.className === 'alpha') {
word = convertWordToMorse(word)
}
if (e.target.id === 'test') {
word = convertWordToMorse(e.target.innerText)
}
console.log(word);
playMorseWord(word)
}

View file

@ -31,7 +31,6 @@ function ModePicker() {
button.classList.add('selected')
} else { button.classList.remove('selected')}
})
console.log("Switched to " + e.target.id + " mode.");
}
return (

View file

@ -1,4 +1,4 @@
import React, { useContext, useEffect } from "react"
import React, { useContext } from "react"
import DitDahDisplay from "./DitDahDisplay"
import morseCode from '../data/morse-reverse.json'
import {MorseBufferContext} from "../contexts/morseBufferContext"

View file

@ -1,5 +1,4 @@
import React, {useContext, useState} from "react"
// import MorseCard from './MorseCard'
import React, {useContext} from "react"
import morseCode from '../data/morse-reverse.json'
import {MorseBufferContext} from "../contexts/morseBufferContext"
@ -8,7 +7,6 @@ export default (function MorseHistoryTextBox() {
const {morseWords, setMorseWords} = useContext(MorseBufferContext)
let text = ''
let span = []
function clearHistory() {
setMorseWords([])
@ -36,10 +34,6 @@ export default (function MorseHistoryTextBox() {
}
})
// try {
// document.getElementById('morseHistory').innerText = text
// } catch {}
return (
<div id="morse-history">
<div id="morseHistory-textbox">{text}</div>

View file

@ -1,6 +1,4 @@
import React from "react"
import KeyTypePicker from "./KeyTypePicker"
import WordsPerMinute from "./WordsPerMinute"
export default (function Options() {

View file

@ -25,7 +25,6 @@ export default (function PlayMorseInput() {
}
})
let a = morse.map(i => i.trim()).join(' ').replace(/ \/ /g,'/').replace(/ \?/g,'?')
console.log(a);
setMorseTranslation(a)
}, [inputValue])
@ -51,7 +50,7 @@ export default (function PlayMorseInput() {
</div>
<div id="input">
<input type="text" id='morseInput' value={inputValue} onChange={handleChange} placeholder="Type here." maxLength="25"/> <i className="ri-play-fill" onClick={handlePlay}></i>
<i class="ri-stop-fill" onClick={() => playMorseWord('')}></i>
<i className="ri-stop-fill" onClick={() => playMorseWord('')}></i>
</div>
<div id="morseTranslation">
<span id="morseTrans">

View file

@ -2,7 +2,6 @@ import React, { useState } from "react"
import Info from "./Info"
import PlayMorseInput from "./PlayMorseInput"
import Legend from "./Legend"
import Options from "./Options"
export default (function SidebarLeft() {

13
src/components/Tip.js Normal file
View file

@ -0,0 +1,13 @@
import React, { useContext } from "react"
import { KeyTypeContext } from "../contexts/keyTypeContext"
export default(function Tip() {
const {keyType} = useContext(KeyTypeContext)
let tip = (keyType === 'straight') ? "Tap the button to use the telegraph." : "Tap each button to use the telegraph."
return (
<span id='tip'>{tip}</span>
)
})

View file

@ -23,16 +23,16 @@ export default React.memo(function WordListPicker() {
setOrder(e.target.id)
} else {
setWordListCategory(e.target.value)
console.log("Switched to " + e.target.value + " word list.");
}
}
let wordLists = ['alphabet', 'numbers', 'boys', 'girls', 'common100', 'test', 'short']
let wordLists = ['alphabet', 'numbers', 'boys', 'girls', 'startrek', 'common100', 'test', 'short']
const metadata = {
'alphabet': {name: 'Alphabet', description: 'Each letter of the alphabet', count: 26},
'numbers': {name: 'Numbers', description: '0-9', count: 10},
'boys': {name: 'Boys Names', description: 'Top 20 Boys Names', count: 20},
'girls': {name: 'Girls Names', description: 'Top 20 Girls Names', count: 20},
'startrek': {name: 'Star Trek', description: 'Word list from the Star Trek universe', count: 20},
'common100': {name: 'Common 100', description: '100 most common words', count: 100},
'test': {name: 'Test List', description: 'A test list', count: 5},
'short': {name: 'Short List', description: 'A short list', count: 1}

View file

@ -3,7 +3,6 @@ import { WPMContext } from "../contexts/wpmContext";
import useMorsePlayer from "../hooks/useMorsePlayer";
export default React.memo(function WordsPerMinute(props) {
console.log('WordsPerMinute rendered');
const {wpm, setWPM} = useContext(WPMContext)
const {playMorseWord} = useMorsePlayer()

View file

@ -1,7 +1,5 @@
import React, {useState, useContext} from "react"
import { GameClockContext } from "./gameClockContext"
import { WordFeederContext } from "./wordFeederContext"
import { KeyTypeContext } from "./keyTypeContext";
import { MorseBufferContext } from "./morseBufferContext";
import morseCode from '../data/morse-reverse.json'
@ -9,7 +7,6 @@ import morseCode from '../data/morse-reverse.json'
const ChallengeContext = React.createContext()
function ChallengeContextProvider(props) {
console.log('ChallengeContextProvider');
const [challengeState, setChallengeState] = useState('ready')
const {resetFeeder} = useContext(WordFeederContext)
@ -28,7 +25,6 @@ function ChallengeContextProvider(props) {
function startChallenge() {
console.log('STARTCHALLENGE');
let countdown
let count = 3
@ -94,13 +90,10 @@ function ChallengeContextProvider(props) {
if (morseLetter === challengeLetter) {
correctCharIndexes.push(index-offset)
console.log('morseCharBuffer', morseCharBuffer);
document.getElementById('challengeWord').childNodes[index-offset].classList.add('correct')
// incorrectCharIndex = null
}
else {
// incorrectCharIndex = index-offset
incorrectMorseIndexes.push(index)
if (incorrectMorseIndexes.length > 0) {
setMorseCharBuffer(prev => {

View file

@ -1,6 +1,5 @@
import React, {useState, useContext, useEffect} from "react"
import { ChallengeContext } from "./challengeContext"
// import { KeyTypeContext } from "./keyTypeContext"
const GameClockContext = React.createContext()
function GameClockContextProvider(props) {
@ -12,9 +11,7 @@ function GameClockContextProvider(props) {
function startGameClock() {
console.log('before clock');
if (!clockIsRunning) {
console.log('after clock');
setClockIsRunning(true)
setIntervals(prev => [...prev, (setInterval(() => {
if (document.getElementById('gameClock') === null) {
@ -61,6 +58,7 @@ function GameClockContextProvider(props) {
default:
return
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [challengeState])

View file

@ -3,7 +3,6 @@ import React, {useState} from "react"
const KeyTypeContext = React.createContext()
function KeyTypeContextProvider(props) {
console.log('KeyTypeContextProvider');
const [keyType, setKeyType] = useState('straight')

View file

@ -4,6 +4,7 @@ import numbers from '../data/numbers.json'
import common100 from '../data/common100.json'
import boys from '../data/names_boys.json'
import girls from '../data/names_girls.json'
import trek from '../data/startrek.json'
const WordListPickerContext = React.createContext()
@ -23,6 +24,8 @@ function WordListPickerContextProvider(props) {
wordList = boys.words
} else if (wordListCategory === 'girls') {
wordList = girls.words
} else if (wordListCategory === 'startrek') {
wordList = trek.words
} else if (wordListCategory === 'common100') {
wordList = common100.words
} else if (wordListCategory === 'test') {

View file

@ -265,6 +265,10 @@ html, body {
margin-bottom: 2em;
}
#main-content .sidebar#left #sidebar-container #sidebar-content #info p span.ditdah {
font-family: "Courier", monospace;
}
#main-content .sidebar#left #sidebar-container #sidebar-content #info img {
width: 50%;
image-rendering: optimizeSpeed;
@ -692,14 +696,10 @@ i[class*="ri-"] {
background: #f4f4f4;
margin: 0px;
border: 0px;
-webkit-transition: width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 40ms ease-out;
transition: width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 40ms ease-out;
transition: transform 40ms ease-out, box-shadow 40ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out;
transition: transform 40ms ease-out, box-shadow 40ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 40ms ease-out;
}
#morseButton button:hover {
background: rgba(112, 128, 144, 0.2);
-webkit-transition: width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 500ms ease-out;
transition: width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 500ms ease-out;
transition: transform 40ms ease-out, box-shadow 500ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out;
transition: transform 40ms ease-out, box-shadow 500ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out, -webkit-transform 40ms ease-out, -webkit-box-shadow 500ms ease-out;
}
#morseButton button.showPaddles {
@ -715,6 +715,8 @@ i[class*="ri-"] {
#morseButton button#left {
border-radius: 50px 0 0 50px;
width: 50%;
-webkit-transition: all 500ms ease-out;
transition: all 500ms ease-out;
}
#morseButton button#left.showPaddles {
@ -723,8 +725,10 @@ i[class*="ri-"] {
}
#morseButton button#right {
width: 50%;
border-radius: 0 50px 50px 0;
width: 50%;
-webkit-transition: all 500ms ease-out;
transition: all 500ms ease-out;
}
#morseButton button#right.showPaddles {
@ -822,7 +826,7 @@ i[class*="ri-"] {
align-items: center;
width: 45%;
padding: 1.7em;
height: 40%;
height: 35%;
background: #eee;
margin-top: 25%;
border-radius: 5px;

File diff suppressed because one or more lines are too long

22
src/data/startrek.json Normal file
View file

@ -0,0 +1,22 @@
{
"words": [
"dilithium",
"borg",
"replicator",
"ensign",
"warbird",
"picard",
"ferengi",
"hypospray",
"tribble",
"starfleet",
"engage",
"holodeck",
"warp",
"enterprise",
"cochran",
"quadrant",
"futile",
"klingon"
]
}

View file

@ -1,34 +0,0 @@
{
"words": [
"am",
"and",
"big",
"bit",
"but",
"cat",
"did",
"eat",
"frog",
"green",
"hand",
"hog",
"is",
"like",
"little",
"map",
"meet",
"nose",
"pet",
"ran",
"rip",
"see",
"six",
"some",
"stop",
"that",
"then",
"try",
"when",
"you"
]
}

View file

@ -39,20 +39,6 @@ function useElectronicKey() {
// let gapTimerRunning = false
let paddlesReleasedSimultaneously = false
// function consoleLogVars() {
// // Log variables (Debug tool)
// console.log('<VARS>');
// console.log('leftIsPressed', leftIsPressed);
// console.log('rightIsPressed', rightIsPressed);
// console.log('queueRunning', queueRunning);
// console.log('queue', queue);
// console.log('pressedFirst', pressedFirst);
// console.log('gapTime', gapTime);
// console.log('paddlesReleasedSimultaneously', paddlesReleasedSimultaneously);
// console.log('</VARS>');
// };
let currentPromise = Promise.resolve()
// Audio Setup
@ -64,18 +50,6 @@ function useElectronicKey() {
} else {
context = null
}
// let frequency = config.frequency
let toneTimer = 0
let toneTime = 0
let start = 0
let end = 0
function getTime() {
let today = new Date()
return today.getMilliseconds()
}
// Promisify playing Dits and Dahs
function play(ditDah) {
@ -114,17 +88,6 @@ function useElectronicKey() {
})
}
function clearHistory() {
setMorseWords([])
}
function stopToneTimer() {
clearInterval(toneTimer)
end = toneTime
console.log('toneTime:', start, end);
toneTime = 0
}
function playWithSpaces(ditDah) {
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
@ -320,7 +283,6 @@ function useElectronicKey() {
if (depressSyncTime < 10) {
paddlesReleasedSimultaneously = true
queue.pop()
console.log('paddles released', queue);
}
depressSyncTime = 0
}

View file

@ -1,131 +0,0 @@
import config from '../config.json'
import { WPMContext } from '../contexts/wpmContext.js';
import { useContext } from 'react';
function useMorsePlayerCopy() {
const {wpm} = useContext(WPMContext)
// const ditMaxTime = 85 //config.ditMaxTime
const ditMaxTime = 1200/wpm
// Tone Setup
let AudioContext = window.AudioContext || window.webkitAudioContext
window.AudioContext = window.AudioContext || window.webkitAudioContext;
let context
if (AudioContext) {
context = new AudioContext()
} else {
context = null
}
let frequency = config.frequency
function play(ditDah) {
let length = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
// length = 1
// return new Promise((resolve, reject) => {
if (context.state === 'interrupted') {
context.resume()
}
let o
o = context.createOscillator()
o.frequency.value = frequency
o.type = "sine"
// o.onended = () => {
// resolve()
// }
let startTime = context.currentTime;
let g = context.createGain()
g.gain.exponentialRampToValueAtTime(config.mainVolume, startTime)
g.gain.setValueAtTime(config.mainVolume, startTime)
o.connect(g)
g.connect(context.destination)
o.start(startTime)
// g.gain.setTargetAtTime(0.0001, startTime + length/1000, 0.001)
// o.stop(startTime + length/1000 + 0.05)
setTimeout(() => {
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.009)
o.stop(context.currentTime + 0.05)
}, length)
// })
}
function playMorseWord(morse) {
let chars = Array.from(morse)
// let currentPromise = Promise.resolve();
let soundQueue = []
let delay = 0
let firstWord = true
for (let i = 0; i < chars.length; i++) {
// currentPromise = currentPromise.then(() => {
// return playChar(chars[i]);
// });
let char = chars[i]
if (char === '.') {
if (firstWord) {
firstWord = false
// soundQueue.push(
setTimeout(() => {
play(char)
}, 0)
// )
} else {
// soundQueue.push(
setTimeout(() => {
play(char)
}, delay)
// )
}
delay += ditMaxTime*2
} else if (char === '-') {
if (firstWord) {
firstWord = false
// soundQueue.push(
setTimeout(() => {
play(char)
}, 0)
// )
} else {
// soundQueue.push(
setTimeout(() => {
play(char)
}, delay)
// )
}
delay += ditMaxTime*4
} else if (char === ' ') {
setTimeout(() => {
}, delay)
delay += ditMaxTime*3
}
}
function playChar(char) {
let delay = (char === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
return new Promise(function(resolve) {
if (char === '.' || char === '-') {
play(char)
.then(setTimeout(() => {
resolve();
}, delay))
} else {
setTimeout(() => {
resolve();
}, delay)
}
});
}
}
return { play }
}
export default useMorsePlayerCopy

View file

@ -1,7 +1,6 @@
import {useEffect} from "react"
import useTelegraph from './hooks/useTelegraph'
function usePracticeMode() {
const {morseCharBuffer, setMorseWords, morseWords, setMorseCharBuffer} = useTelegraph()
@ -11,7 +10,6 @@ function usePracticeMode() {
if (morseCharBuffer.slice(-1) === '/') {
// Remove forward slash
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
console.log('val: ', val);
setMorseWords(prev => [val, ...prev])
@ -22,7 +20,6 @@ function usePracticeMode() {
setMorseCharBuffer('')
}
// setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
// eslint-disable-next-line
}, [morseCharBuffer])
}

View file

@ -39,18 +39,11 @@ function useStraightKey() {
let o // Oscillator Node
let g // Gain Node
// let frequency = config.frequency
let isRunning = false
function clearHistory() {
setMorseWords([])
}
function handleInputStart(event) {
// event.preventDefault()
console.log(event.keyCode);
if (event.keyCode === 32) {
if (document.activeElement.id === 'morseInput') {
@ -62,10 +55,7 @@ function useStraightKey() {
}
}
if (isRunning) {
// console.log('insideBufferDisplay', insideBufferDisplay);
return
} else {
if ((event.keyCode !== 32 &&
@ -110,13 +100,6 @@ function useStraightKey() {
}
function handleInputEnd(event) {
// event.preventDefault()
// if (event.target.id !== 'morseBufferDisplay') {
// insideBufferDisplay = true
// console.log('insideBufferDisplay', insideBufferDisplay);
// }
// if (!insideBufferDisplay) {return}
if (isRunning) {
if ((event.keyCode !== 32 &&
@ -130,8 +113,6 @@ function useStraightKey() {
isRunning = false
// console.log('charTime:', charTime);
if (charTime <= ditMaxTime) {
setMorseCharBuffer(prev => prev + '.')
} else {
@ -217,7 +198,6 @@ function useStraightKey() {
clearInterval(charTimer)
clearInterval(gapTimer)
// clearHistory()
}
// eslint-disable-next-line
}, [wpm, gameMode, frequency])

View file

@ -1,173 +0,0 @@
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 (mode === 'practice' && gapTime >= wordGapMaxTime) {
setMorseCharBuffer(prev => prev + '/')
clearInterval(gapTimer)
gapTimer = 0
gapTime = 0
}
if (mode === 'challenge' && gapTime >= letterGapMinTime) {
setMorseCharBuffer(prev => prev + '_')
clearInterval(gapTimer)
gapTimer = 0
gapTime = 0
}
}, timingUnit);
}
function checkGapBetweenInputs() {
// Check Gap between letters
if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) {
if (mode === 'practice') {
setMorseCharBuffer(prev => prev + ' ')
} else if (mode === 'challenge') {
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)
clearHistory()
}
// eslint-disable-next-line
}, [])
useEffect(() => {
// PRACTICE MODE
if (morseCharBuffer.slice(-1) === '/' && mode === 'practice') {
// Remove forward slash
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
setMorseWords(prev => [val, ...prev])
if (morseWords.length >= morseHistorySize) {
setMorseWords(prev => prev.slice(0,prev.length-1))
}
setMorseCharBuffer('')
}
console.log('morseCharBuffer:', morseCharBuffer, '|');
// CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js
// else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') {
// }
// eslint-disable-next-line
}, [morseCharBuffer])
return {morseCharBuffer, morseWords, clearHistory, setMorseCharBuffer, setMorseWords}
}
export default useTelegraph

View file

@ -219,15 +219,14 @@ html, body {
#info {
// border: 1px solid red;
// margin-left: 20px;
// padding: 1.5em;
height: fit-content;
padding: 2.5em;
font-family: $main-font;
font-size: 1.2rem;
line-height: 1.5em;
opacity: 100%;
// overflow-y: scroll;
transition: all 500ms ease-in-out;
h1, h2 {
@ -242,6 +241,9 @@ html, body {
}
p {
margin-bottom: 2em;
span.ditdah {
font-family: $ditDah-font;
}
}
img {
width: 50%;
@ -254,68 +256,6 @@ html, body {
}
}
}
// .sidebar#right {
// border: 1px solid green;
// background: $main-bg-color-light;
// box-shadow: -3px 0px 5px rgba(0,0,0,0.2);
// display: flex;
// flex-direction: column;
// justify-content: space-between;
// position: fixed;
// top: 0px;
// margin-top: 50px;
// padding: 1em;
// padding-top: 50px;
// // left: calc(100vw - 30%);
// right: 0;
// height: calc(100% - 5em);
// min-width: 400px;
// max-width: 100%;
// width: 30%;
// z-index: 100;
// transition: all 500ms ease-in-out;
// #mainOptions {
// h1 {
// margin-bottom: 0.3em;
// }
// transition: all 500ms ease-in-out;
// opacity: 100%;
// }
// &.hide {
// right: calc(-30% + 43px);
// #mainOptions {
// opacity: 0%;
// }
// // top: 50px;
// #settings {
// transform: rotateZ(270deg);
// }
// }
// #settings-icon {
// // border: 1px solid red;
// width: fit-content;
// height: fit-content;
// position: absolute;
// top: 10px;
// left: 5px;
// transition: all 500ms ease-in-out;
// transition: transform 200ms ease-in-out;
// &:hover {
// transform: scale(1.1);
// i {color: #333;}
// }
// i {
// font-size: 2rem;
// }
// }
// }
#main-interface {
// border: 1px solid red;
@ -683,11 +623,7 @@ $button-radius: 50px;
margin: 0px;
border: 0px;
// transition: all 20ms ease-out;
transition: transform 40ms ease-out, box-shadow 40ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out;
&:hover {
background: rgba(112, 128, 144, 0.2);
}
transition: transform 40ms ease-out, box-shadow 500ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out;
&.showPaddles {
color: #888;
@ -700,6 +636,7 @@ $button-radius: 50px;
&#left {
border-radius: $button-radius 0 0 $button-radius;
width: 50%;
transition: all 500ms ease-out;
// background: red;
&.showPaddles{
margin-right: 7px;
@ -707,9 +644,10 @@ $button-radius: 50px;
}
}
&#right {
width: 50%;
// background: blue;
border-radius: 0 $button-radius $button-radius 0;
width: 50%;
transition: all 500ms ease-out;
// background: blue;
&.showPaddles{
margin-left: 7px;
border-radius: 20px;
@ -848,7 +786,7 @@ $button-radius: 50px;
width: 45%;
padding: 1.7em;
height: 40%;
height: 35%;
background: $main-bg-color-light;
// background: #fefefe;
margin-top: 25%;