mirror of
https://github.com/genemecija/learn-morse-code.git
synced 2025-12-06 07:02:00 +01:00
Code commenting and cleanup
This commit is contained in:
parent
7e99454e9f
commit
900312c471
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
|
|
@ -1,19 +1,19 @@
|
||||||
import React, {useContext} from 'react';
|
import React, {useContext} from 'react';
|
||||||
import '../css/App.css';
|
import '../css/App.css';
|
||||||
import ChallengeWord from '../components/ChallengeWord'
|
|
||||||
import ChallengeBufferDisplay from '../components/ChallengeBufferDisplay';
|
|
||||||
import GameClock from '../components/GameClock';
|
|
||||||
import { KeyTypeContext } from '../contexts/keyTypeContext';
|
|
||||||
import StraightKey from '../components/StraightKey';
|
|
||||||
import ElectronicKey from '../components/ElectronicKey';
|
|
||||||
import ChallengeControls from '../components/ChallengeControls';
|
|
||||||
import { ChallengeContext } from '../contexts/challengeContext';
|
import { ChallengeContext } from '../contexts/challengeContext';
|
||||||
|
import { KeyTypeContext } from '../contexts/keyTypeContext';
|
||||||
|
import ChallengeBufferDisplay from '../components/ChallengeBufferDisplay';
|
||||||
|
import ChallengeControls from '../components/ChallengeControls';
|
||||||
|
import ChallengeWord from '../components/ChallengeWord'
|
||||||
|
import ElectronicKey from '../components/ElectronicKey';
|
||||||
|
import GameClock from '../components/GameClock';
|
||||||
|
import StraightKey from '../components/StraightKey';
|
||||||
|
|
||||||
|
|
||||||
export default React.memo(function ChallengeMode() {
|
export default React.memo(function ChallengeMode() {
|
||||||
|
|
||||||
const {keyType} = useContext(KeyTypeContext)
|
const {keyType} = useContext(KeyTypeContext)
|
||||||
const {challengeState, cancelChallenge, morseArray, incorrectMorseIndexes, challengeWordClass} = useContext(ChallengeContext)
|
const {challengeState, cancelChallenge, morseArray, challengeWordClass} = useContext(ChallengeContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -25,7 +25,7 @@ export default React.memo(function ChallengeMode() {
|
||||||
<ChallengeControls cancelChallenge={cancelChallenge} />
|
<ChallengeControls cancelChallenge={cancelChallenge} />
|
||||||
</div>
|
</div>
|
||||||
<ChallengeWord challengeWordClass={challengeWordClass} />
|
<ChallengeWord challengeWordClass={challengeWordClass} />
|
||||||
<ChallengeBufferDisplay morseArray={morseArray} incorrectMorseIndexes={incorrectMorseIndexes} />
|
<ChallengeBufferDisplay morseArray={morseArray} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import '../css/App.css';
|
import '../css/App.css';
|
||||||
import MorseBufferDisplay from '../components/MorseBufferDisplay'
|
|
||||||
import MorseHistoryTextBox from '../components/MorseHistory_textbox'
|
|
||||||
import { KeyTypeContext } from '../contexts/keyTypeContext';
|
import { KeyTypeContext } from '../contexts/keyTypeContext';
|
||||||
import StraightKey from '../components/StraightKey';
|
|
||||||
import ElectronicKey from '../components/ElectronicKey';
|
import ElectronicKey from '../components/ElectronicKey';
|
||||||
|
import MorseBufferDisplay from '../components/MorseBufferDisplay'
|
||||||
|
import MorseHistoryTextBox from '../components/MorseHistory'
|
||||||
|
import StraightKey from '../components/StraightKey';
|
||||||
|
|
||||||
|
|
||||||
export default (function PracticeMode(props) {
|
export default (function PracticeMode() {
|
||||||
|
|
||||||
const {keyType} = useContext(KeyTypeContext)
|
const {keyType} = useContext(KeyTypeContext)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import '../css/App.css';
|
|
||||||
import useStraightKey from '../hooks/useStraightKey';
|
|
||||||
import GameClock from '../components/GameClock'
|
|
||||||
import MorseBufferDisplay from '../components/MorseBufferDisplay'
|
|
||||||
import MorseHistory from '../components/MorseHistory'
|
|
||||||
|
|
||||||
function TrainingMode() {
|
|
||||||
|
|
||||||
const {morseCharBuffer, morseWords} = useStraightKey('timed')
|
|
||||||
|
|
||||||
console.log('TrainingMode.js rendered')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<GameClock time={30} />
|
|
||||||
<MorseBufferDisplay buffer={morseCharBuffer} /><br/>
|
|
||||||
<MorseHistory morseWords={morseWords} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default React.memo(TrainingMode);
|
|
||||||
|
|
@ -1,31 +1,19 @@
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import morseCode from '../data/morse-reverse.json'
|
|
||||||
|
|
||||||
export default React.memo(function ChallengeBufferDisplay(props) {
|
export default React.memo(function ChallengeBufferDisplay(props) {
|
||||||
|
|
||||||
const morseArray = props.morseArray
|
const morseArray = props.morseArray
|
||||||
let incorrectMorseIndexes = props.incorrectMorseIndexes
|
|
||||||
|
|
||||||
let ditDahs = []
|
let ditDahs = []
|
||||||
let alphanumeric = []
|
|
||||||
|
|
||||||
for (let i in morseArray) {
|
for (let i in morseArray) {
|
||||||
let morseChar = morseArray[i]
|
let morseChar = morseArray[i]
|
||||||
|
|
||||||
// Alphanumeric
|
|
||||||
let alpha = morseCode[morseChar] || '[?]'
|
|
||||||
let alphaClass = (incorrectMorseIndexes.includes(Number(i))) ? 'strike morseError' : ''
|
|
||||||
alphanumeric.push(<span key={i} className={alphaClass}>{alpha.toUpperCase()}</span>)
|
|
||||||
|
|
||||||
// DitDahs
|
ditDahs.push(<span key={i}>{morseChar}</span>)
|
||||||
let ditDahClass = (incorrectMorseIndexes.includes(Number(i))) ? 'morseError' : ''
|
|
||||||
ditDahs.push(<span key={i} className={ditDahClass}>{morseChar}</span>)
|
|
||||||
// ditDahs.push(<span key={i+100} className='space'> </span>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="challengeBufferDisplay">
|
<div id="challengeBufferDisplay">
|
||||||
{/* <div id="overlay"></div> */}
|
|
||||||
<div id="ditDahs">
|
<div id="ditDahs">
|
||||||
{ditDahs}
|
{ditDahs}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { GameClockContext } from "../contexts/gameClockContext"
|
||||||
import { ChallengeContext } from "../contexts/challengeContext"
|
import { ChallengeContext } from "../contexts/challengeContext"
|
||||||
import { WordListPickerContext } from "../contexts/wordListPickerContext"
|
import { WordListPickerContext } from "../contexts/wordListPickerContext"
|
||||||
|
|
||||||
export default (function ChallengeComplete(props) {
|
export default (function ChallengeComplete() {
|
||||||
|
|
||||||
const {gameClockTime} = useContext(GameClockContext)
|
const {gameClockTime} = useContext(GameClockContext)
|
||||||
const {setChallengeState} = useContext(ChallengeContext)
|
const {setChallengeState} = useContext(ChallengeContext)
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import React from "react"
|
|
||||||
import morseCode from '../data/morse-reverse.json'
|
|
||||||
import ChallengeBufferDisplay from "./ChallengeBufferDisplay";
|
|
||||||
|
|
||||||
export default React.memo(function ChallengeDisplay(props) {
|
|
||||||
|
|
||||||
let morseLetters = props.buffer.split('_').filter(l => l !== '')
|
|
||||||
let challengeLetters = props.word.split('')
|
|
||||||
let correctIndexes = []
|
|
||||||
let incorrectIndex = null
|
|
||||||
|
|
||||||
morseLetters.forEach((morseLetter, index) => {
|
|
||||||
let morseAlpha = morseCode[morseLetter]
|
|
||||||
let challengeLetter = challengeLetters[index].toLowerCase()
|
|
||||||
|
|
||||||
if (morseAlpha === challengeLetter) {
|
|
||||||
correctIndexes.push(index)
|
|
||||||
} else {
|
|
||||||
if (props.buffer.slice(-1) === "_") {
|
|
||||||
incorrectIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let spannedWord = challengeLetters.map((letter,index) => {
|
|
||||||
let className = 'cLetter'
|
|
||||||
className += (correctIndexes.includes(index)) ? ' correct' : ''
|
|
||||||
className += (incorrectIndex === index) ? ' morseError' : ''
|
|
||||||
return (
|
|
||||||
<span key={index} className={className} id={"chal"+index}>{letter}</span>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div id="challengeWord">{spannedWord}</div>
|
|
||||||
<ChallengeBufferDisplay buffer={props.buffer.slice(0,-1).replace(/_/g, ' ')} incorrectIndex={incorrectIndex} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useContext } from "react"
|
import React, { useContext } from "react"
|
||||||
import ChallengeReady from "./ChallengeReady"
|
|
||||||
import { ChallengeContext } from "../contexts/challengeContext"
|
import { ChallengeContext } from "../contexts/challengeContext"
|
||||||
|
import ChallengeReady from "./ChallengeReady"
|
||||||
import ChallengeComplete from "./ChallengeComplete"
|
import ChallengeComplete from "./ChallengeComplete"
|
||||||
|
|
||||||
export default (function ChallengeOverlay() {
|
export default (function ChallengeOverlay() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useContext } from "react"
|
import React, { useContext } from "react"
|
||||||
import WordListPicker from "./WordListPicker"
|
|
||||||
import { ChallengeContext } from "../contexts/challengeContext"
|
import { ChallengeContext } from "../contexts/challengeContext"
|
||||||
|
import WordListPicker from "./WordListPicker"
|
||||||
|
|
||||||
export default (function ChallengeReady() {
|
export default (function ChallengeReady() {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,7 @@ export default React.memo(function ChallengeWord(props) {
|
||||||
challengeLetters = word.split('')
|
challengeLetters = word.split('')
|
||||||
}
|
}
|
||||||
|
|
||||||
let spannedWord = challengeLetters.map((letter,index) => {
|
let spannedWord = challengeLetters.map((letter,index) => <span key={index} className='cLetter'>{letter}</span>)
|
||||||
return (
|
|
||||||
<span key={index} className='cLetter'>{letter}</span>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="challengeWord" className={props.challengeWordClass}>{spannedWord}</div>
|
<div id="challengeWord" className={props.challengeWordClass}>{spannedWord}</div>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,6 @@
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
function DitDahDisplay(props) {
|
export default (function DitDahDisplay(props) {
|
||||||
if (props.dd === ' ') {
|
|
||||||
return (
|
|
||||||
<div className='ditDah'> </div>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div className='ditDah'>{props.dd}</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DitDahDisplay
|
return (props.dd === ' ') ? <div className='ditDah'> </div> : <div className='ditDah'>{props.dd}</div>
|
||||||
|
})
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react'
|
import React from "react"
|
||||||
import useElectronicKey from '../hooks/useElectronicKey';
|
import useElectronicKey from '../hooks/useElectronicKey';
|
||||||
|
|
||||||
export default React.memo(function ElectronicKey(props) {
|
export default React.memo(function ElectronicKey() {
|
||||||
|
|
||||||
useElectronicKey()
|
useElectronicKey()
|
||||||
})
|
})
|
||||||
|
|
@ -26,9 +26,9 @@ export default (function Footer() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
App by Gene Mecija •
|
app by @genemecija •
|
||||||
Code: <span id="contact-icons"><i id="github" onClick={handleClick} className={contactLinks['github']['icon']}></i></span> •
|
contact <span id="contact-icons"><i id="twitter" onClick={handleClick} className={contactLinks['twitter']['icon']}></i> <i id="email" onClick={handleClick} className={contactLinks['email']['icon']}></i></span> •
|
||||||
Say Hi! <span id="contact-icons"><i id="twitter" onClick={handleClick} className={contactLinks['twitter']['icon']}></i> <i id="email" onClick={handleClick} className={contactLinks['email']['icon']}></i></span>
|
code <span id="contact-icons"><i id="github" onClick={handleClick} className={contactLinks['github']['icon']}></i></span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -5,8 +5,8 @@ export default React.memo(function FrequencyPicker(props) {
|
||||||
|
|
||||||
const {frequency, setFrequency} = useContext(FrequencyContext)
|
const {frequency, setFrequency} = useContext(FrequencyContext)
|
||||||
|
|
||||||
const maxFreq = 1500
|
|
||||||
const minFreq = 300
|
const minFreq = 300
|
||||||
|
const maxFreq = 1500
|
||||||
|
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
if (Number(e.target.value) > maxFreq) {
|
if (Number(e.target.value) > maxFreq) {
|
||||||
|
|
@ -16,10 +16,9 @@ export default React.memo(function FrequencyPicker(props) {
|
||||||
} else {
|
} else {
|
||||||
setFrequency(Number(e.target.value))
|
setFrequency(Number(e.target.value))
|
||||||
}
|
}
|
||||||
// setFrequency(Number(e.target.value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function increment() {
|
function increment() {
|
||||||
// setFrequency(prevFreq => prevFreq + 10)
|
|
||||||
setFrequency(prevFreq => {
|
setFrequency(prevFreq => {
|
||||||
if (prevFreq + 10 <= maxFreq) {
|
if (prevFreq + 10 <= maxFreq) {
|
||||||
return (prevFreq + 10)
|
return (prevFreq + 10)
|
||||||
|
|
@ -28,8 +27,8 @@ export default React.memo(function FrequencyPicker(props) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrement() {
|
function decrement() {
|
||||||
// setFrequency(prevFreq => prevFreq - 10)
|
|
||||||
setFrequency(prevFreq => {
|
setFrequency(prevFreq => {
|
||||||
if (prevFreq - 10 >= minFreq) {
|
if (prevFreq - 10 >= minFreq) {
|
||||||
return (prevFreq - 10)
|
return (prevFreq - 10)
|
||||||
|
|
@ -38,7 +37,6 @@ export default React.memo(function FrequencyPicker(props) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='frequency' className='mode-picker'>
|
<div id='frequency' className='mode-picker'>
|
||||||
|
|
|
||||||
|
|
@ -59,13 +59,11 @@ export default (function Header () {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="title">
|
<div id="title">
|
||||||
Learn Morse Code
|
Learn Morse Code
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="social-links">
|
<div id="social-links">
|
||||||
Share: <span id="share-icons">{contacts}</span>
|
Share: <span id="share-icons">{contacts}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export default React.memo(function Info() {
|
||||||
return (
|
return (
|
||||||
<div id="info">
|
<div id="info">
|
||||||
<h1>Morse Code</h1>
|
<h1>Morse Code</h1>
|
||||||
<p>Morse code is a method of communication that uses short and long tones. This tool will help beginners learn Morse code.</p>
|
<p>Morse code is a method of communication that uses short tones (dits) and long tones (dahs) in various sequences to make letters, numbers, and special characters. This tool will help beginners learn Morse code.</p>
|
||||||
|
|
||||||
<h2>Dits and Dahs</h2>
|
<h2>Dits and Dahs</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -19,7 +19,7 @@ export default React.memo(function Info() {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Spacing</h2 >
|
<h2>Spacing</h2 >
|
||||||
<p>The spacing between dits and dahs matters in Morse Code. Spacing of various lengths signify different things.<br/>
|
<p>The spacing between dits and dahs matters in Morse code. Spacing of various lengths signify different things.<br/>
|
||||||
|
|
||||||
<span className="bold">Intra-character Spacing</span> A letter in Morse code can be made up of multiple dits and dahs. The spaces between the dits and dahs that make up a single letter are each the length of one dit. E.g., three dits, each separated by one-dit-long spaces, is an "S". (<span className="ditdah">...</span>) <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i><br />
|
<span className="bold">Intra-character Spacing</span> A letter in Morse code can be made up of multiple dits and dahs. The spaces between the dits and dahs that make up a single letter are each the length of one dit. E.g., three dits, each separated by one-dit-long spaces, is an "S". (<span className="ditdah">...</span>) <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i><br />
|
||||||
|
|
||||||
|
|
@ -34,12 +34,12 @@ export default React.memo(function Info() {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Telegraph Key Types</h2 >
|
<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>
|
<center><img src={straight_key} alt="Straight Key" /></center>
|
||||||
<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>
|
<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>
|
<center><img src={electronic_key} alt="Electronic Key"></img></center>
|
||||||
<p><b>Electronic Keys</b> use paddles that automatically generate dits and dahs when pressed. The Electronic Keyer used here is an Iambic keyer that uses two paddles–left paddle for dits, right paddle for dahs. Pressing both paddles simultaneously alternates between dit and dah. Switch between the two at the appropriate times to build letters in Morse Code.</p>
|
<p><b>Electronic Keys</b> use paddles that automatically generate dits and dahs when pressed. The Electronic Keyer used here is an Iambic keyer that uses two paddles–left paddle for dits, right paddle for dahs. Pressing both paddles simultaneously automatically alternates between dit and dah. Switch between the two paddles at the appropriate times to build letters in Morse code.</p>
|
||||||
|
|
||||||
<p>Check out <a href='https://www.youtube.com/watch?v=uEy4Wvy6uUg' target='_blank' rel="noopener noreferrer">this video</a> for a demonstration of the difference between Straight and Electronic keys.</p>
|
<p>Check out <a href='https://www.youtube.com/watch?v=uEy4Wvy6uUg' target='_blank' rel="noopener noreferrer">this video</a> for a demonstration of the difference between Straight and Electronic keys.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,18 @@ export default React.memo(function KeyTypePicker() {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="keyType" className="mode-picker">
|
<div id="keyType" className="mode-picker">
|
||||||
<div id="title">
|
<div id="title">
|
||||||
Key Type
|
Key Type
|
||||||
</div>
|
|
||||||
<div id="buttons">
|
|
||||||
<button id="straight" onClick={handleClick}>
|
|
||||||
Straight Key
|
|
||||||
</button>
|
|
||||||
<button id="electronic" onClick={handleClick}>
|
|
||||||
Electronic Key
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="buttons">
|
||||||
|
<button id="straight" onClick={handleClick}>
|
||||||
|
Straight Key
|
||||||
|
</button>
|
||||||
|
<button id="electronic" onClick={handleClick}>
|
||||||
|
Electronic Key
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -3,7 +3,7 @@ import React from "react"
|
||||||
import morseCode from '../data/morse-code.json'
|
import morseCode from '../data/morse-code.json'
|
||||||
import useMorsePlayer from "../hooks/useMorsePlayer";
|
import useMorsePlayer from "../hooks/useMorsePlayer";
|
||||||
|
|
||||||
function Legend() {
|
export default React.memo(function Legend() {
|
||||||
|
|
||||||
const { playMorseWord } = useMorsePlayer()
|
const { playMorseWord } = useMorsePlayer()
|
||||||
|
|
||||||
|
|
@ -15,10 +15,6 @@ function Legend() {
|
||||||
if (e.target.className === 'alpha') {
|
if (e.target.className === 'alpha') {
|
||||||
word = convertWordToMorse(word)
|
word = convertWordToMorse(word)
|
||||||
}
|
}
|
||||||
if (e.target.id === 'test') {
|
|
||||||
word = convertWordToMorse(e.target.innerText)
|
|
||||||
}
|
|
||||||
|
|
||||||
playMorseWord(word)
|
playMorseWord(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,17 +65,15 @@ function Legend() {
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="legend">
|
<div id="legend">
|
||||||
<div id="legend-title">
|
<div id="legend-title">
|
||||||
Legend
|
Legend
|
||||||
</div>
|
|
||||||
<div id="legend-items">
|
|
||||||
{letters}
|
|
||||||
{numbers}
|
|
||||||
{special}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="legend-items">
|
||||||
|
{letters}
|
||||||
|
{numbers}
|
||||||
|
{special}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
export default React.memo(Legend)
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import React, {useContext} from "react"
|
import React, {useContext} from "react"
|
||||||
import {GameModeContext} from "../contexts/gameModeContext"
|
import { ChallengeContext } from "../contexts/challengeContext"
|
||||||
|
import { GameClockContext } from "../contexts/gameClockContext"
|
||||||
|
import { GameModeContext } from "../contexts/gameModeContext"
|
||||||
import { MorseBufferContext } from "../contexts/morseBufferContext"
|
import { MorseBufferContext } from "../contexts/morseBufferContext"
|
||||||
import { WordFeederContext } from "../contexts/wordFeederContext"
|
import { WordFeederContext } from "../contexts/wordFeederContext"
|
||||||
import { GameClockContext } from "../contexts/gameClockContext"
|
|
||||||
import { ChallengeContext } from "../contexts/challengeContext"
|
|
||||||
|
|
||||||
function ModePicker() {
|
export default React.memo(function ModePicker() {
|
||||||
|
|
||||||
const {setGameMode} = useContext(GameModeContext)
|
const {setGameMode} = useContext(GameModeContext)
|
||||||
const {setMorseCharBuffer} = useContext(MorseBufferContext)
|
const {setMorseCharBuffer} = useContext(MorseBufferContext)
|
||||||
|
|
@ -34,20 +34,18 @@ function ModePicker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="gameMode" className="mode-picker">
|
<div id="gameMode" className="mode-picker">
|
||||||
<div id="title">
|
<div id="title">
|
||||||
Mode
|
Mode
|
||||||
</div>
|
|
||||||
<div id='buttons'>
|
|
||||||
<button id="practice" className="selected" onClick={handleClick}>
|
|
||||||
Practice Mode
|
|
||||||
</button>
|
|
||||||
<button id="challenge" onClick={handleClick}>
|
|
||||||
Challenge Mode
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id='buttons'>
|
||||||
|
<button id="practice" className="selected" onClick={handleClick}>
|
||||||
|
Practice Mode
|
||||||
|
</button>
|
||||||
|
<button id="challenge" onClick={handleClick}>
|
||||||
|
Challenge Mode
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
export default React.memo(ModePicker)
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext } from "react"
|
import React, { useContext } from "react"
|
||||||
|
import { MorseBufferContext } from "../contexts/morseBufferContext"
|
||||||
import DitDahDisplay from "./DitDahDisplay"
|
import DitDahDisplay from "./DitDahDisplay"
|
||||||
import morseCode from '../data/morse-reverse.json'
|
import morseCode from '../data/morse-reverse.json'
|
||||||
import {MorseBufferContext} from "../contexts/morseBufferContext"
|
|
||||||
|
|
||||||
export default React.memo(function MorseBufferDisplay() {
|
export default React.memo(function MorseBufferDisplay() {
|
||||||
|
|
||||||
|
|
@ -18,7 +18,6 @@ export default React.memo(function MorseBufferDisplay() {
|
||||||
alphanumeric += ' '
|
alphanumeric += ' '
|
||||||
} else {
|
} else {
|
||||||
if (morseCode[letters[i]] === undefined) {
|
if (morseCode[letters[i]] === undefined) {
|
||||||
// alphanumeric += '[?]'
|
|
||||||
alphanumeric += (letters[i] === '' ? '':'[?]')
|
alphanumeric += (letters[i] === '' ? '':'[?]')
|
||||||
} else {
|
} else {
|
||||||
alphanumeric += morseCode[letters[i]]
|
alphanumeric += morseCode[letters[i]]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default React.memo(function MorseButtons() {
|
||||||
<button className="paddle" id="right"></button>
|
<button className="paddle" id="right"></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="morseButtonText">
|
<div id="morseButtonText">
|
||||||
TAP OR PRESS SPACEBAR
|
TAP BUTTON OR PRESS SPACEBAR
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, {useContext} from "react"
|
import React, {useContext} from "react"
|
||||||
|
import { MorseBufferContext } from "../contexts/morseBufferContext"
|
||||||
import morseCode from '../data/morse-reverse.json'
|
import morseCode from '../data/morse-reverse.json'
|
||||||
import {MorseBufferContext} from "../contexts/morseBufferContext"
|
|
||||||
|
|
||||||
export default (function MorseHistoryTextBox() {
|
export default (function MorseHistoryTextBox() {
|
||||||
|
|
||||||
|
|
@ -12,6 +12,7 @@ export default (function MorseHistoryTextBox() {
|
||||||
setMorseWords([])
|
setMorseWords([])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate Morse History contents
|
||||||
morseWords.forEach((word, index) => {
|
morseWords.forEach((word, index) => {
|
||||||
if (word.includes(' ')) {
|
if (word.includes(' ')) {
|
||||||
let newWord = ''
|
let newWord = ''
|
||||||
|
|
@ -23,14 +24,11 @@ export default (function MorseHistoryTextBox() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
text = newWord + ' ' + text
|
text = newWord + ' ' + text
|
||||||
// span.splice(0, 0, <span key={index}>{newWord}</span>)
|
|
||||||
}
|
}
|
||||||
else if (morseCode[word] === undefined) {
|
else if (morseCode[word] === undefined) {
|
||||||
text = '[?] ' + text
|
text = '[?] ' + text
|
||||||
// span.splice(0, 0, <span key={index}>[?]</span>)
|
|
||||||
} else {
|
} else {
|
||||||
text = morseCode[word].toUpperCase() + ' ' + text
|
text = morseCode[word].toUpperCase() + ' ' + text
|
||||||
// span.splice(0, 0, <span key={index}>{morseCode[word].toUpperCase()}</span>)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import React from "react"
|
|
||||||
|
|
||||||
export default (function Options() {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div id="mainOptions">
|
|
||||||
<div id="mainOptions-title">Options</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -10,10 +10,22 @@ export default (function PlayMorseInput() {
|
||||||
|
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
setInputValue(e.target.value)
|
setInputValue(e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handlePlay() {
|
||||||
|
playMorseWord(morseTranslation)
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertWordToMorse(word) {
|
||||||
|
let morse = ''
|
||||||
|
for (let i in word) {
|
||||||
|
morse += morseCode[word[i].toLowerCase()]
|
||||||
|
}
|
||||||
|
return morse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Live translation of text into morse code
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let arr = Array.from(inputValue.trim().toLowerCase())
|
let arr = Array.from(inputValue.trim().toLowerCase())
|
||||||
let morse = arr.map(item => {
|
let morse = arr.map(item => {
|
||||||
|
|
@ -29,34 +41,20 @@ export default (function PlayMorseInput() {
|
||||||
|
|
||||||
}, [inputValue])
|
}, [inputValue])
|
||||||
|
|
||||||
function handlePlay() {
|
|
||||||
playMorseWord(morseTranslation)
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertWordToMorse(word) {
|
|
||||||
let morse = ''
|
|
||||||
for (let i in word) {
|
|
||||||
morse += morseCode[word[i].toLowerCase()]
|
|
||||||
// morse += ' '
|
|
||||||
}
|
|
||||||
return morse
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="playMorseInput">
|
<div id="playMorseInput">
|
||||||
<div id="title">
|
<div id="title">
|
||||||
<h2>Translate To Morse</h2>
|
<h2>Translate To Morse</h2>
|
||||||
</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 className="ri-stop-fill" onClick={() => playMorseWord('')}></i>
|
|
||||||
</div>
|
|
||||||
<div id="morseTranslation">
|
|
||||||
<span id="morseTrans">
|
|
||||||
{morseTranslation === '' ? 'Morse translation will appear here.' : morseTranslation.replace(/\?/g,'[?]').replace(/\] /g,']')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</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 className="ri-stop-fill" onClick={() => playMorseWord('')}></i>
|
||||||
|
</div>
|
||||||
|
<div id="morseTranslation">
|
||||||
|
<span id="morseTrans">
|
||||||
|
{morseTranslation === '' ? 'Morse translation will appear here.' : morseTranslation.replace(/\?/g,'[?]').replace(/\] /g,']')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
import React, { useState } from "react"
|
import React, { useState } from "react"
|
||||||
import Info from "./Info"
|
import Info from "./Info"
|
||||||
import PlayMorseInput from "./PlayMorseInput"
|
|
||||||
import Legend from "./Legend"
|
import Legend from "./Legend"
|
||||||
|
import PlayMorseInput from "./PlayMorseInput"
|
||||||
|
|
||||||
export default (function SidebarLeft() {
|
export default (function SidebarLeft() {
|
||||||
|
|
||||||
const [sidebarContent, setSidebarContent] = useState('nav-learn')
|
const [sidebarContent, setSidebarContent] = useState('nav-learn')
|
||||||
|
|
||||||
|
// Hide/show sidebar
|
||||||
function toggleLeft() {
|
function toggleLeft() {
|
||||||
document.querySelector('.sidebar#left').classList.toggle('hide')
|
document.querySelector('.sidebar#left').classList.toggle('hide')
|
||||||
document.querySelector('#main-interface').classList.toggle('expandLeft')
|
document.querySelector('#main-interface').classList.toggle('expandLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle sidebar navigation selection
|
||||||
function navClicked(e) {
|
function navClicked(e) {
|
||||||
if (e.target.id === 'nav-learn') {
|
if (e.target.id === 'nav-learn') {
|
||||||
setSidebarContent('nav-learn')
|
setSidebarContent('nav-learn')
|
||||||
|
|
@ -19,8 +22,8 @@ export default (function SidebarLeft() {
|
||||||
} else {
|
} else {
|
||||||
setSidebarContent('nav-play')
|
setSidebarContent('nav-play')
|
||||||
}
|
}
|
||||||
|
|
||||||
let navItems = document.querySelector(".navbar").childNodes
|
let navItems = document.querySelector(".navbar").childNodes
|
||||||
|
|
||||||
navItems.forEach(item => {
|
navItems.forEach(item => {
|
||||||
if (item.id === e.target.id) {
|
if (item.id === e.target.id) {
|
||||||
item.classList.add('selected')
|
item.classList.add('selected')
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react'
|
import React from "react"
|
||||||
import useStraightKey from '../hooks/useStraightKey';
|
import useStraightKey from '../hooks/useStraightKey';
|
||||||
|
|
||||||
export default React.memo(function StraightKey(props) {
|
export default React.memo(function StraightKey() {
|
||||||
|
|
||||||
useStraightKey()
|
useStraightKey()
|
||||||
})
|
})
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
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>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React, {useContext} from "react"
|
||||||
import { WordListPickerContext } from "../contexts/wordListPickerContext";
|
import { WordListPickerContext } from "../contexts/wordListPickerContext";
|
||||||
import { WordFeederContext } from "../contexts/wordFeederContext";
|
import { WordFeederContext } from "../contexts/wordFeederContext";
|
||||||
|
|
||||||
export default React.memo(function WordCountPicker(props) {
|
export default React.memo(function WordCountPicker() {
|
||||||
|
|
||||||
const {setWordListCount, wordListCountMax} = useContext(WordListPickerContext)
|
const {setWordListCount, wordListCountMax} = useContext(WordListPickerContext)
|
||||||
const {resetFeeder} = useContext(WordFeederContext)
|
const {resetFeeder} = useContext(WordFeederContext)
|
||||||
|
|
@ -12,7 +12,7 @@ export default React.memo(function WordCountPicker(props) {
|
||||||
setWordListCount(e.target.value)
|
setWordListCount(e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Options for Select Input
|
// Create Options for Select element
|
||||||
let options = []
|
let options = []
|
||||||
for (let i = 0; i < wordListCountMax; i++) {
|
for (let i = 0; i < wordListCountMax; i++) {
|
||||||
options.push(<option value={i+1} key={i}>{i+1}</option>)
|
options.push(<option value={i+1} key={i}>{i+1}</option>)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export default React.memo(function WordListPicker() {
|
||||||
function handleClick(e) {
|
function handleClick(e) {
|
||||||
resetFeeder()
|
resetFeeder()
|
||||||
|
|
||||||
|
// Handle Word List Order selection
|
||||||
if (orderOpts.includes(e.target.id)) {
|
if (orderOpts.includes(e.target.id)) {
|
||||||
let buttons = document.querySelector(".mode-picker#wordOrderPicker #buttons").childNodes
|
let buttons = document.querySelector(".mode-picker#wordOrderPicker #buttons").childNodes
|
||||||
buttons.forEach(button => {
|
buttons.forEach(button => {
|
||||||
|
|
@ -20,15 +21,16 @@ export default React.memo(function WordListPicker() {
|
||||||
button.classList.add('selected')
|
button.classList.add('selected')
|
||||||
} else { button.classList.remove('selected')}
|
} else { button.classList.remove('selected')}
|
||||||
})
|
})
|
||||||
|
|
||||||
setOrder(e.target.id)
|
setOrder(e.target.id)
|
||||||
} else {
|
}
|
||||||
|
// Handle Word List Category selection
|
||||||
|
else {
|
||||||
setWordListCategory(e.target.value)
|
setWordListCategory(e.target.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let wordLists = Object.keys(metadata)
|
let wordLists = Object.keys(metadata)
|
||||||
|
// Create Option elements for Select element
|
||||||
let options = wordLists.map((wl, index) => (<option value={wl} key={index}>{metadata[wl]['name']}</option>))
|
let options = wordLists.map((wl, index) => (<option value={wl} key={index}>{metadata[wl]['name']}</option>))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -68,14 +70,6 @@ export default React.memo(function WordListPicker() {
|
||||||
{metadata[wordListCategory]['description']}
|
{metadata[wordListCategory]['description']}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <div id="wordlist-count" className="mode-picker">
|
|
||||||
<div id="title">
|
|
||||||
# of List Items:
|
|
||||||
</div>
|
|
||||||
<div id="info">
|
|
||||||
{metadata[wordListCategory]['count']}
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -2,15 +2,15 @@ import React, {useContext} from "react"
|
||||||
import { WPMContext } from "../contexts/wpmContext";
|
import { WPMContext } from "../contexts/wpmContext";
|
||||||
import useMorsePlayer from "../hooks/useMorsePlayer";
|
import useMorsePlayer from "../hooks/useMorsePlayer";
|
||||||
|
|
||||||
export default React.memo(function WordsPerMinute(props) {
|
export default React.memo(function WordsPerMinute() {
|
||||||
|
|
||||||
const {wpm, setWPM} = useContext(WPMContext)
|
const {wpm, setWPM} = useContext(WPMContext)
|
||||||
const {playMorseWord} = useMorsePlayer()
|
const {playMorseWord} = useMorsePlayer()
|
||||||
const maxWPM = 30
|
|
||||||
const minWPM = 5
|
const minWPM = 5
|
||||||
|
const maxWPM = 30
|
||||||
|
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
// setWPM(Number(e.target.value))
|
|
||||||
if (Number(e.target.value) > maxWPM) {
|
if (Number(e.target.value) > maxWPM) {
|
||||||
setWPM(maxWPM)
|
setWPM(maxWPM)
|
||||||
} else if (Number(e.target.value) < minWPM) {
|
} else if (Number(e.target.value) < minWPM) {
|
||||||
|
|
@ -19,8 +19,8 @@ export default React.memo(function WordsPerMinute(props) {
|
||||||
setWPM(Number(e.target.value))
|
setWPM(Number(e.target.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function increment() {
|
function increment() {
|
||||||
// setWPM(prevWPM => prevWPM + 1)
|
|
||||||
setWPM(prevWPM => {
|
setWPM(prevWPM => {
|
||||||
if (prevWPM + 1 <= maxWPM) {
|
if (prevWPM + 1 <= maxWPM) {
|
||||||
return (prevWPM + 1)
|
return (prevWPM + 1)
|
||||||
|
|
@ -30,7 +30,6 @@ export default React.memo(function WordsPerMinute(props) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function decrement() {
|
function decrement() {
|
||||||
// setWPM(prevWPM => prevWPM - 1)
|
|
||||||
setWPM(prevWPM => {
|
setWPM(prevWPM => {
|
||||||
if (prevWPM - 1 >= minWPM) {
|
if (prevWPM - 1 >= minWPM) {
|
||||||
return (prevWPM - 1)
|
return (prevWPM - 1)
|
||||||
|
|
@ -39,10 +38,8 @@ export default React.memo(function WordsPerMinute(props) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// <input id='wpm-input' type='text' value={wpm} onChange={handleChange} />
|
|
||||||
<div id='wpm' className='mode-picker'>
|
<div id='wpm' className='mode-picker'>
|
||||||
<div id='title'>
|
<div id='title'>
|
||||||
WPM <span id="range">({minWPM}-{maxWPM})</span>
|
WPM <span id="range">({minWPM}-{maxWPM})</span>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,4 @@
|
||||||
{
|
{
|
||||||
"timingUnit": 1,
|
|
||||||
"ditMaxTime": 60,
|
|
||||||
"mainVolume": 0.2,
|
"mainVolume": 0.2,
|
||||||
"frequency": 650.0,
|
|
||||||
"practiceSpeed": {
|
|
||||||
"slow": 40,
|
|
||||||
"normal": 24,
|
|
||||||
"fast": 17
|
|
||||||
},
|
|
||||||
"historySize": 50
|
"historySize": 50
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +111,7 @@ function ChallengeContextProvider(props) {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Next word once all correct
|
// Retrieve next word once all characters are correct
|
||||||
if (correctCharIndexes.length === challengeLetters.length) {
|
if (correctCharIndexes.length === challengeLetters.length) {
|
||||||
challengeWordClass = 'correct'
|
challengeWordClass = 'correct'
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ function GameClockContextProvider(props) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setGameClockTime(prev => prev + 1)
|
setGameClockTime(prev => prev + 1)
|
||||||
// document.getElementById('gameClock').innerText = Number(gameClockTime) //Number(document.getElementById('gameClock').innerText) + 1
|
|
||||||
}, 1000))
|
}, 1000))
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -31,14 +30,14 @@ function GameClockContextProvider(props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear game clock intervals
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
// clearInterval(gameClockTimer)
|
|
||||||
// setGameClockTimer(0)
|
|
||||||
for (let i = 0; i < intervals.length; i++) {
|
for (let i = 0; i < intervals.length; i++) {
|
||||||
clearInterval(intervals[i]);
|
clearInterval(intervals[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger game clock changes on challenge state change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (challengeState) {
|
switch (challengeState) {
|
||||||
case 'ready':
|
case 'ready':
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,14 @@ const WordFeederContext = React.createContext()
|
||||||
|
|
||||||
function WordFeederContextProvider(props) {
|
function WordFeederContextProvider(props) {
|
||||||
|
|
||||||
// let wordList = ['hi', 'morse', 'code', 'hello', 'gene']
|
|
||||||
const {wordList, wordListShuffled} = useContext(WordListPickerContext)
|
const {wordList, wordListShuffled} = useContext(WordListPickerContext)
|
||||||
|
|
||||||
const [wordIndex, setWordIndex] = useState(0)
|
const [wordIndex, setWordIndex] = useState(0)
|
||||||
const [order, setOrder] = useState('sequential')
|
const [order, setOrder] = useState('sequential')
|
||||||
let word
|
let word
|
||||||
|
|
||||||
|
// Set word list ordered appropriately
|
||||||
if (order === 'sequential') {
|
if (order === 'sequential') {
|
||||||
// word = wordList[wordIndex]
|
|
||||||
if (wordList[wordIndex] === undefined) {
|
if (wordList[wordIndex] === undefined) {
|
||||||
word = [wordList[0]]
|
word = [wordList[0]]
|
||||||
}
|
}
|
||||||
|
|
@ -21,7 +20,6 @@ function WordFeederContextProvider(props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (order === 'random') {
|
else if (order === 'random') {
|
||||||
// word = wordListShuffled[wordIndex]
|
|
||||||
if (wordListShuffled[wordIndex] === undefined) {
|
if (wordListShuffled[wordIndex] === undefined) {
|
||||||
word = [wordListShuffled[0]]
|
word = [wordListShuffled[0]]
|
||||||
}
|
}
|
||||||
|
|
@ -36,20 +34,8 @@ function WordFeederContextProvider(props) {
|
||||||
|
|
||||||
function getNextWord() {
|
function getNextWord() {
|
||||||
setWordIndex(prev => prev + 1)
|
setWordIndex(prev => prev + 1)
|
||||||
// if (order === 'sequential') {
|
|
||||||
// } else if (order === 'random') {
|
|
||||||
// setWordIndex(prev => prev + 1)
|
|
||||||
// if (wordListShuffled[wordIndex] === undefined) {
|
|
||||||
// alert('NULL2')
|
|
||||||
// word = '!end'
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// word = wordListShuffled[wordIndex]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WordFeederContext.Provider value={{word: word, getNextWord: getNextWord, resetFeeder: resetFeeder, setOrder: setOrder}}>
|
<WordFeederContext.Provider value={{word: word, getNextWord: getNextWord, resetFeeder: resetFeeder, setOrder: setOrder}}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@ function WordListPickerContextProvider(props) {
|
||||||
const [wordListCount, setWordListCount] = useState(10)
|
const [wordListCount, setWordListCount] = useState(10)
|
||||||
|
|
||||||
let wordList = []
|
let wordList = []
|
||||||
const testList = ['gene', 'anya', 'ali', 'liam', 'last']
|
|
||||||
const short = ['gene']
|
|
||||||
|
|
||||||
|
|
||||||
if (wordListCategory === 'alphabet') {
|
if (wordListCategory === 'alphabet') {
|
||||||
wordList = alphabet.words
|
wordList = alphabet.words
|
||||||
|
|
@ -31,10 +28,6 @@ function WordListPickerContextProvider(props) {
|
||||||
wordList = trek.words
|
wordList = trek.words
|
||||||
} else if (wordListCategory === 'common100') {
|
} else if (wordListCategory === 'common100') {
|
||||||
wordList = common100.words
|
wordList = common100.words
|
||||||
} else if (wordListCategory === 'test') {
|
|
||||||
wordList = testList
|
|
||||||
} else if (wordListCategory === 'short') {
|
|
||||||
wordList = short
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wordListCountMax = wordList.length
|
const wordListCountMax = wordList.length
|
||||||
|
|
@ -45,12 +38,10 @@ function WordListPickerContextProvider(props) {
|
||||||
'boys': {name: 'Boys Names', description: 'Popular Boys Names'},
|
'boys': {name: 'Boys Names', description: 'Popular Boys Names'},
|
||||||
'girls': {name: 'Girls Names', description: 'Popular Girls Names'},
|
'girls': {name: 'Girls Names', description: 'Popular Girls Names'},
|
||||||
'startrek': {name: 'Star Trek', description: 'Star Trek universe'},
|
'startrek': {name: 'Star Trek', description: 'Star Trek universe'},
|
||||||
'common100': {name: 'Common Words', description: '100 Most Common Words'},
|
'common100': {name: 'Common Words', description: '100 Most Common Words'}
|
||||||
'test': {name: 'Test List', description: 'A test list'},
|
|
||||||
'short': {name: 'Short List', description: 'A short list'}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle input array and return
|
||||||
function randomize(arr) {
|
function randomize(arr) {
|
||||||
let array = [...arr]
|
let array = [...arr]
|
||||||
let currentIndex = array.length, temporaryValue, randomIndex;
|
let currentIndex = array.length, temporaryValue, randomIndex;
|
||||||
|
|
@ -67,7 +58,6 @@ function WordListPickerContextProvider(props) {
|
||||||
array[currentIndex] = array[randomIndex];
|
array[currentIndex] = array[randomIndex];
|
||||||
array[randomIndex] = temporaryValue;
|
array[randomIndex] = temporaryValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
145
src/css/App.css
145
src/css/App.css
|
|
@ -24,6 +24,7 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
|
width: 100vw;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
|
|
@ -35,7 +36,6 @@ html, body {
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100vw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
|
|
@ -91,7 +91,7 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#header #social-links i:hover {
|
#header #social-links i:hover {
|
||||||
color: goldenrod;
|
color: gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header #social-links div {
|
#header #social-links div {
|
||||||
|
|
@ -340,18 +340,19 @@ html, body {
|
||||||
image-rendering: optimizeSpeed;
|
image-rendering: optimizeSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-content .sidebar#left #sidebar-container #sidebar-content #info i:hover {
|
|
||||||
color: goldenrod;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-content .sidebar#left #sidebar-container #sidebar-content #info a:visited {
|
#main-content .sidebar#left #sidebar-container #sidebar-content #info a:visited {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-content .sidebar#left #sidebar-container #sidebar-content #info a:hover {
|
#main-content .sidebar#left #sidebar-container #sidebar-content #info a:hover, #main-content .sidebar#left #sidebar-container #sidebar-content #info i:hover {
|
||||||
color: goldenrod;
|
color: goldenrod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main-content .sidebar#left #sidebar-container #sidebar-content #info i {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
#main-content #main-interface {
|
#main-content #main-interface {
|
||||||
background: whitesmoke;
|
background: whitesmoke;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
|
@ -821,6 +822,7 @@ i[class*="ri-"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
#morseButtonText {
|
#morseButtonText {
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
|
@ -1146,11 +1148,6 @@ i[class*="ri-"] {
|
||||||
background: #5ae65a;
|
background: #5ae65a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tip {
|
|
||||||
font-size: 2rem;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
#morseBufferDisplay {
|
#morseBufferDisplay {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
|
|
@ -1232,8 +1229,8 @@ i[class*="ri-"] {
|
||||||
width: 30px !important;
|
width: 30px !important;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -1297,8 +1294,8 @@ i[class*="ri-"] {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -1316,17 +1313,6 @@ i[class*="ri-"] {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.strike {
|
|
||||||
text-decoration: line-through;
|
|
||||||
opacity: 30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseError {
|
|
||||||
background: rgba(255, 0, 0, 0.4);
|
|
||||||
color: #780000;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#morse-history {
|
#morse-history {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
|
|
@ -1372,8 +1358,8 @@ i[class*="ri-"] {
|
||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#morse-history #clear {
|
#morse-history #clear {
|
||||||
|
|
@ -1390,6 +1376,7 @@ i[class*="ri-"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
#morse-history #clear #message {
|
#morse-history #clear #message {
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
padding: 0.3em;
|
padding: 0.3em;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
color: #777;
|
color: #777;
|
||||||
|
|
@ -1445,99 +1432,17 @@ i[class*="ri-"] {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.morseCard {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-orient: horizontal !important;
|
|
||||||
-webkit-box-direction: normal !important;
|
|
||||||
-ms-flex-direction: row !important;
|
|
||||||
flex-direction: row !important;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
font-size: 1.6rem;
|
|
||||||
font-family: "Courier Prime", Courier, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard .ditDahs-container, .morseCard .alphanumeric-container {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
width: 50%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard .alphanumeric-container span {
|
|
||||||
padding-top: 0.17em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard .ditDahs-container {
|
|
||||||
-webkit-box-pack: end;
|
|
||||||
-ms-flex-pack: end;
|
|
||||||
justify-content: flex-end;
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard div div {
|
|
||||||
padding: 3px;
|
|
||||||
margin: 2px;
|
|
||||||
background: #fdfdfd;
|
|
||||||
white-space: nowrap;
|
|
||||||
border-radius: 3px;
|
|
||||||
-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: 1em;
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard div div span.morseError {
|
|
||||||
background: rgba(255, 0, 0, 0.4);
|
|
||||||
height: 1.7rem;
|
|
||||||
color: #780000;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard .ditDahs {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-pack: end;
|
|
||||||
-ms-flex-pack: end;
|
|
||||||
justify-content: flex-end;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
font-family: "Courier", monospace;
|
|
||||||
font-weight: bold;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.morseCard .ditDahs span.space {
|
|
||||||
border-radius: 3px;
|
|
||||||
background: #eee;
|
|
||||||
opacity: 0.5;
|
|
||||||
width: 3px;
|
|
||||||
margin-left: 4px;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1024px) {
|
@media only screen and (max-width: 1024px) {
|
||||||
#root #main-content .sidebar#left #sidebar-container #sidebar-content #info {
|
#sidebar-content #info {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
#root #main-content .sidebar#left #sidebar-container #sidebar-content #playerAndLegend {
|
#sidebar-content #playerAndLegend {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
#root #main-content .sidebar#left #sidebar-container #sidebar-content #playerAndLegend #legend #legend-items button {
|
#sidebar-content #playerAndLegend #legend #legend-items button {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
}
|
}
|
||||||
#root #main-content #main-interface #mainOptions {
|
#mainOptions {
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-box-direction: normal;
|
-webkit-box-direction: normal;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
|
|
@ -1720,6 +1625,11 @@ i[class*="ri-"] {
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
max-height: 2em;
|
max-height: 2em;
|
||||||
}
|
}
|
||||||
|
#root #main-content #main-interface #morse-history #clear button {
|
||||||
|
padding: 0px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
#root #main-content #main-interface #challenge-header {
|
#root #main-content #main-interface #challenge-header {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
@ -1737,5 +1647,10 @@ i[class*="ri-"] {
|
||||||
#root #main-content #main-interface #challengeWord span {
|
#root #main-content #main-interface #challengeWord span {
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
}
|
}
|
||||||
|
#root #main-content #main-interface #morseButton {
|
||||||
|
margin-top: 0;
|
||||||
|
-webkit-transform: scale(0.85);
|
||||||
|
transform: scale(0.85);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*# sourceMappingURL=App.css.map */
|
/*# sourceMappingURL=App.css.map */
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,42 +1,40 @@
|
||||||
import {useEffect, useContext} from 'react'
|
import {useEffect, useContext} from 'react'
|
||||||
import {MorseBufferContext} from '../contexts/morseBufferContext'
|
|
||||||
import config from '../config.json'
|
|
||||||
import { WPMContext } from '../contexts/wpmContext'
|
|
||||||
import { GameModeContext } from '../contexts/gameModeContext'
|
|
||||||
import { FrequencyContext } from '../contexts/frequencyContext'
|
import { FrequencyContext } from '../contexts/frequencyContext'
|
||||||
|
import { GameModeContext } from '../contexts/gameModeContext'
|
||||||
|
import { MorseBufferContext } from '../contexts/morseBufferContext'
|
||||||
|
import { WPMContext } from '../contexts/wpmContext'
|
||||||
|
import config from '../config.json'
|
||||||
|
|
||||||
// ELECTRONIC KEY TELEGRAPH - Iambic A
|
// ELECTRONIC KEY TELEGRAPH - Iambic A
|
||||||
|
|
||||||
function useElectronicKey() {
|
export default (function useElectronicKey() {
|
||||||
|
|
||||||
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
|
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
|
||||||
const {wpm} = useContext(WPMContext)
|
const {wpm} = useContext(WPMContext)
|
||||||
const {gameMode} = useContext(GameModeContext)
|
const {gameMode} = useContext(GameModeContext)
|
||||||
const {frequency} = useContext(FrequencyContext)
|
const {frequency} = useContext(FrequencyContext)
|
||||||
|
|
||||||
|
// DitDah length setup
|
||||||
let ditMaxTime = 1200/wpm
|
let ditMaxTime = 1200/wpm
|
||||||
|
|
||||||
|
|
||||||
const timingUnit = config.timingUnit
|
|
||||||
|
|
||||||
let ratio = .2
|
let ratio = .2
|
||||||
const letterGapMinTime = ditMaxTime*ratio*3 //config.practiceSpeed.normal*3
|
const letterGapMinTime = ditMaxTime*ratio*3
|
||||||
const wordGapMaxTime = ditMaxTime*ratio*7 // config.practiceSpeed.normal*7
|
const wordGapMaxTime = ditMaxTime*ratio*7
|
||||||
|
|
||||||
const morseHistorySize = config.historySize
|
const morseHistorySize = config.historySize
|
||||||
|
|
||||||
|
|
||||||
let leftIsPressed = false
|
let leftIsPressed = false
|
||||||
let rightIsPressed = false
|
let rightIsPressed = false
|
||||||
let queueRunning = false
|
let queueRunning = false
|
||||||
let queue = []
|
let queue = []
|
||||||
let pressedFirst = null
|
let pressedFirst = null
|
||||||
|
|
||||||
|
// Timers setup
|
||||||
let depressSyncTime
|
let depressSyncTime
|
||||||
let depressSyncTimer
|
let depressSyncTimer
|
||||||
let depressSyncTimerRunning = false
|
let depressSyncTimerRunning = false
|
||||||
let gapTime = 0
|
let gapTime = 0
|
||||||
let gapTimer = 0
|
let gapTimer = 0
|
||||||
// let gapTimerRunning = false
|
|
||||||
let paddlesReleasedSimultaneously = false
|
let paddlesReleasedSimultaneously = false
|
||||||
|
|
||||||
let currentPromise = Promise.resolve()
|
let currentPromise = Promise.resolve()
|
||||||
|
|
@ -80,14 +78,11 @@ function useElectronicKey() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.001)
|
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.001)
|
||||||
o.stop(context.currentTime + 0.05)
|
o.stop(context.currentTime + 0.05)
|
||||||
|
|
||||||
// start = getTime()
|
|
||||||
}, playDuration)
|
}, playDuration)
|
||||||
// g.gain.setTargetAtTime(0.0001, startTime + playDuration/1000, 0.001)
|
|
||||||
// o.stop(startTime + playDuration/1000 + 0.05)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Play dit or dah with trailing space (silence)
|
||||||
function playWithSpaces(ditDah) {
|
function playWithSpaces(ditDah) {
|
||||||
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
|
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
|
||||||
|
|
||||||
|
|
@ -97,13 +92,6 @@ function useElectronicKey() {
|
||||||
clearInterval(gapTimer)
|
clearInterval(gapTimer)
|
||||||
checkGapBetweenInputs()
|
checkGapBetweenInputs()
|
||||||
setMorseCharBuffer(prev => prev + ditDah)
|
setMorseCharBuffer(prev => prev + ditDah)
|
||||||
|
|
||||||
// // for troubleshooting ditDah length in milliseconds
|
|
||||||
// toneTimer = setInterval(() => {
|
|
||||||
// toneTime += 1
|
|
||||||
// }, 1);
|
|
||||||
// start = toneTime
|
|
||||||
|
|
||||||
|
|
||||||
play(ditDah)
|
play(ditDah)
|
||||||
.then(setTimeout(() => {
|
.then(setTimeout(() => {
|
||||||
|
|
@ -124,7 +112,7 @@ function useElectronicKey() {
|
||||||
gapTimer = 0
|
gapTimer = 0
|
||||||
gapTime = 0
|
gapTime = 0
|
||||||
}
|
}
|
||||||
}, timingUnit)
|
}, 1)
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
}, delay)
|
}, delay)
|
||||||
|
|
@ -165,7 +153,7 @@ function useElectronicKey() {
|
||||||
// Execute queue
|
// Execute queue
|
||||||
queueRunning = true
|
queueRunning = true
|
||||||
for (let i = 0; i < localQueue.length; i++) {
|
for (let i = 0; i < localQueue.length; i++) {
|
||||||
if (paddlesReleasedSimultaneously === true) {
|
if (paddlesReleasedSimultaneously) {
|
||||||
localQueue.pop()
|
localQueue.pop()
|
||||||
clearTimeout(clear)
|
clearTimeout(clear)
|
||||||
cleanup()
|
cleanup()
|
||||||
|
|
@ -176,12 +164,12 @@ function useElectronicKey() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine which paddles are pressed, add to queue, and execute
|
||||||
function sendPressedToQueue() {
|
function sendPressedToQueue() {
|
||||||
if (leftIsPressed && rightIsPressed) {
|
if (leftIsPressed && rightIsPressed) {
|
||||||
if (pressedFirst === 'left') {
|
if (pressedFirst === 'left') {
|
||||||
queue.push('-')
|
queue.push('-')
|
||||||
pressedFirst = null
|
pressedFirst = null
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
queue.push('.')
|
queue.push('.')
|
||||||
queue.push('-')
|
queue.push('-')
|
||||||
|
|
@ -203,7 +191,7 @@ function useElectronicKey() {
|
||||||
if (event.type === 'touchstart') {
|
if (event.type === 'touchstart') {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
paddlesReleasedSimultaneously = false
|
paddlesReleasedSimultaneously = false
|
||||||
|
|
||||||
if (event.keyCode === 188 || event.keyCode === 190) {
|
if (event.keyCode === 188 || event.keyCode === 190) {
|
||||||
|
|
@ -241,9 +229,10 @@ function useElectronicKey() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInputEnd(event) {
|
function handleInputEnd(event) {
|
||||||
if (event.type === 'touchend') {event.preventDefault()}
|
if (event.type === 'touchend') {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
// if (!insideBufferDisplay) {return}
|
|
||||||
if (event.keyCode === 188 || event.target.id === "left") {
|
if (event.keyCode === 188 || event.target.id === "left") {
|
||||||
document.querySelector('.paddle#left').classList.remove('active')
|
document.querySelector('.paddle#left').classList.remove('active')
|
||||||
|
|
||||||
|
|
@ -265,6 +254,8 @@ function useElectronicKey() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timer used to determine if both paddles are released within 10ms
|
||||||
|
// Need to know this to stop Iambic tones at correct time
|
||||||
function startDepressSyncTimer() {
|
function startDepressSyncTimer() {
|
||||||
depressSyncTimerRunning = true
|
depressSyncTimerRunning = true
|
||||||
// Reset depressSyncTime
|
// Reset depressSyncTime
|
||||||
|
|
@ -288,10 +279,11 @@ function useElectronicKey() {
|
||||||
}
|
}
|
||||||
depressSyncTime = 0
|
depressSyncTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check gap between letters to determin if new character or new word
|
||||||
function checkGapBetweenInputs() {
|
function checkGapBetweenInputs() {
|
||||||
// Check Gap between letters
|
|
||||||
if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) {
|
if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) {
|
||||||
// setMorseCharBuffer(prev => prev + ' ')
|
|
||||||
if (gameMode === 'practice') {
|
if (gameMode === 'practice') {
|
||||||
setMorseCharBuffer(prev => prev + ' ')
|
setMorseCharBuffer(prev => prev + ' ')
|
||||||
} else if (gameMode === 'challenge') {
|
} else if (gameMode === 'challenge') {
|
||||||
|
|
@ -303,6 +295,8 @@ function useElectronicKey() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add paddle event listeners and update on WPM, Game Mode, or Frequency change
|
||||||
|
// Not updating on these state changes prevents change from taking effect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('keydown', handleInputStart)
|
document.addEventListener('keydown', handleInputStart)
|
||||||
document.addEventListener('keyup', handleInputEnd)
|
document.addEventListener('keyup', handleInputEnd)
|
||||||
|
|
@ -335,28 +329,20 @@ function useElectronicKey() {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [wpm, gameMode, frequency])
|
}, [wpm, gameMode, frequency])
|
||||||
|
|
||||||
|
// Remove forward slash and move buffer contents to morse words array
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// PRACTICE MODE
|
|
||||||
// if (morseCharBuffer.slice(-1) === '/') {
|
|
||||||
if (morseCharBuffer.slice(-1) === '/' && gameMode === 'practice') {
|
if (morseCharBuffer.slice(-1) === '/' && gameMode === 'practice') {
|
||||||
// Remove forward slash
|
|
||||||
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
|
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
|
||||||
|
|
||||||
setMorseWords(prev => [val, ...prev])
|
setMorseWords(prev => [val, ...prev])
|
||||||
|
|
||||||
|
// Limit history to configured history size
|
||||||
if (morseWords.length >= morseHistorySize) {
|
if (morseWords.length >= morseHistorySize) {
|
||||||
setMorseWords(prev => prev.slice(0,prev.length-1))
|
setMorseWords(prev => prev.slice(0,prev.length-1))
|
||||||
}
|
}
|
||||||
setMorseCharBuffer('')
|
setMorseCharBuffer('')
|
||||||
}
|
}
|
||||||
// CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js
|
|
||||||
// else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [morseCharBuffer])
|
}, [morseCharBuffer])
|
||||||
|
|
||||||
}
|
})
|
||||||
|
|
||||||
export default useElectronicKey
|
|
||||||
|
|
@ -1,344 +0,0 @@
|
||||||
import {useEffect, useContext, useState} from 'react'
|
|
||||||
import config from '../config.json'
|
|
||||||
import {MorseBufferContext} from '../contexts/morseBufferContext'
|
|
||||||
|
|
||||||
// SINGLE/DUAL LEVER TELEGRAPH
|
|
||||||
|
|
||||||
function useElectronicKey(mode = 'practice') {
|
|
||||||
|
|
||||||
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
|
|
||||||
|
|
||||||
const timingUnit = config.timingUnit
|
|
||||||
|
|
||||||
const ditMaxTime = 85 // ditMaxTime * 0.365 to get ms, e.g. 85 * 0.365 ~= 31ms
|
|
||||||
const letterGapMinTime = ditMaxTime*0.36*3 //config.practiceSpeed.normal*3
|
|
||||||
const wordGapMaxTime = ditMaxTime*0.36*7 // config.practiceSpeed.normal*7
|
|
||||||
const morseHistorySize = config.historySize
|
|
||||||
|
|
||||||
let leftIsPressed = false
|
|
||||||
let rightIsPressed = false
|
|
||||||
let queueRunning = false
|
|
||||||
let queue = []
|
|
||||||
let pressedFirst = null
|
|
||||||
|
|
||||||
let depressSyncTime
|
|
||||||
let depressSyncTimer
|
|
||||||
let depressSyncTimerRunning = false
|
|
||||||
let gapTimer = 0
|
|
||||||
let gapTime = 0
|
|
||||||
const [paddlesReleasedSimultaneously, setPaddlesReleasedSimultaneously] = useState(false)
|
|
||||||
|
|
||||||
|
|
||||||
let currentPromise = Promise.resolve()
|
|
||||||
|
|
||||||
// Audio 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 frequency = config.frequency
|
|
||||||
|
|
||||||
let toneTimer = 0
|
|
||||||
let toneTime = 0
|
|
||||||
let start = 0
|
|
||||||
let end = 0
|
|
||||||
|
|
||||||
// Promisify playing Dits and Dahs
|
|
||||||
function play(ditDah) {
|
|
||||||
let playDuration = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (context.state === 'interrupted') {
|
|
||||||
context.resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
let o = context.createOscillator()
|
|
||||||
o.frequency.value = frequency
|
|
||||||
o.type = "sine"
|
|
||||||
o.onended = () => {
|
|
||||||
// clearInterval(toneTimer)
|
|
||||||
// end = toneTime
|
|
||||||
// console.log('duration:', end-start);
|
|
||||||
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)
|
|
||||||
|
|
||||||
// // for troubleshooting ditDah length in milliseconds
|
|
||||||
// toneTimer = setInterval(() => {
|
|
||||||
// toneTime += 1
|
|
||||||
// }, 1);
|
|
||||||
// start = toneTime
|
|
||||||
// // </>
|
|
||||||
|
|
||||||
g.gain.setTargetAtTime(0.0001, startTime + playDuration/1000, 0.001)
|
|
||||||
o.stop(startTime + playDuration/1000 + 0.05)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function playWithSpaces(ditDah) {
|
|
||||||
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
|
|
||||||
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
if (ditDah === '.' || ditDah === '-') {
|
|
||||||
play(ditDah)
|
|
||||||
.then(setTimeout(() => {
|
|
||||||
setMorseCharBuffer(prev => prev + ditDah)
|
|
||||||
resolve();
|
|
||||||
}, delay))
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
// setMorseCharBuffer(prev => prev + ' ')
|
|
||||||
resolve();
|
|
||||||
}, delay)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeQueue() {
|
|
||||||
let localQueue = queue
|
|
||||||
|
|
||||||
// Set waitTime to completion of queue (including spaces)
|
|
||||||
let waitTime = 0
|
|
||||||
for (let i in localQueue) {
|
|
||||||
if (localQueue[i] === '.') {
|
|
||||||
waitTime += ditMaxTime*2
|
|
||||||
} else if (localQueue[i] === '-') {
|
|
||||||
waitTime += ditMaxTime*4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queueRunning = true
|
|
||||||
|
|
||||||
// Wait till completion of queue to execute
|
|
||||||
const clear = setTimeout(() => {
|
|
||||||
queueRunning = false
|
|
||||||
queue = []
|
|
||||||
checkPressed()
|
|
||||||
}, waitTime)
|
|
||||||
|
|
||||||
// Execute queue
|
|
||||||
for (let i = 0; i < localQueue.length; i++) {
|
|
||||||
currentPromise = currentPromise.then(() => {
|
|
||||||
return playWithSpaces(localQueue[i])
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkPressed() {
|
|
||||||
if (leftIsPressed && rightIsPressed) {
|
|
||||||
if (pressedFirst === 'left') {
|
|
||||||
queue.push('-')
|
|
||||||
if (!paddlesReleasedSimultaneously) {
|
|
||||||
console.log('one');
|
|
||||||
queue.push('.')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
queue.push('.')
|
|
||||||
if (!paddlesReleasedSimultaneously) {
|
|
||||||
console.log('two');
|
|
||||||
queue.push('-')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (leftIsPressed && !rightIsPressed) {
|
|
||||||
queue.push('.')
|
|
||||||
}
|
|
||||||
else if (rightIsPressed && !leftIsPressed) {
|
|
||||||
queue.push('-')
|
|
||||||
}
|
|
||||||
if (queue.length > 0) {
|
|
||||||
executeQueue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// function depressSyncTimeout() {
|
|
||||||
// let depressSyncTimeO = setTimeout(() => {
|
|
||||||
// if (testQueue.length > 0) {
|
|
||||||
// let x = testQueue.shift()
|
|
||||||
// console.log('testQueue', x, testQueue);
|
|
||||||
// depressSyncTimeout()
|
|
||||||
// } else {
|
|
||||||
// clearTimeout(depressSyncTimeO)
|
|
||||||
// }
|
|
||||||
// }, 1000)
|
|
||||||
// }
|
|
||||||
|
|
||||||
function handleInputStart(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
// if (event.keyCode === 188) {
|
|
||||||
// depressSyncTimeout()
|
|
||||||
// }
|
|
||||||
// else if (event.keyCode === 190) {
|
|
||||||
// testQueue.push('.')
|
|
||||||
// console.log('testQueue', testQueue);
|
|
||||||
// }
|
|
||||||
// else if (event.target.id === 'morseButton') {
|
|
||||||
// testQueue = []
|
|
||||||
// }
|
|
||||||
// while (testQueue.length > 0) {
|
|
||||||
// currentPromise = currentPromise.then(() => {
|
|
||||||
// return playWithSpaces(testQueue.shift())
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
setPaddlesReleasedSimultaneously(false)
|
|
||||||
|
|
||||||
if (event.repeat) { return }
|
|
||||||
|
|
||||||
// if (!leftIsPressed && !rightIsPressed) {
|
|
||||||
// clearInterval(gapTimer)
|
|
||||||
// checkGapBetweenInputs()
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (event.keyCode === 188) {
|
|
||||||
leftIsPressed = true
|
|
||||||
if (!rightIsPressed) { pressedFirst = 'left'}
|
|
||||||
|
|
||||||
// Prevent further input if queue is executing
|
|
||||||
if (!queueRunning) {
|
|
||||||
checkPressed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event.keyCode === 190) {
|
|
||||||
rightIsPressed = true
|
|
||||||
if (!leftIsPressed) { pressedFirst = 'right'}
|
|
||||||
|
|
||||||
// Prevent further input if queue is executing
|
|
||||||
if (!queueRunning) {
|
|
||||||
checkPressed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function startDepressSyncTimer() {
|
|
||||||
depressSyncTimerRunning = true
|
|
||||||
// Reset depressSyncTime
|
|
||||||
depressSyncTime = 0
|
|
||||||
// Start depressSyncTimer
|
|
||||||
depressSyncTimer = setInterval(() => {
|
|
||||||
depressSyncTime += 1
|
|
||||||
if (depressSyncTime > 20) {
|
|
||||||
depressSyncTimerRunning = false
|
|
||||||
clearInterval(depressSyncTimer)
|
|
||||||
depressSyncTime = 0
|
|
||||||
}
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
function stopDepressSyncTimer() {
|
|
||||||
depressSyncTimerRunning = false
|
|
||||||
clearInterval(depressSyncTimer)
|
|
||||||
if (depressSyncTime < 10) {
|
|
||||||
setPaddlesReleasedSimultaneously(true)
|
|
||||||
}
|
|
||||||
depressSyncTime = 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) {
|
|
||||||
console.log('letterGapMinTime <= gapTime < wordGapMaxTime:',letterGapMinTime, gapTime, wordGapMaxTime);
|
|
||||||
if (mode === 'practice') {
|
|
||||||
setMorseCharBuffer(prev => prev + ' ')
|
|
||||||
} else if (mode === 'challenge') {
|
|
||||||
console.log("UNDERSCORE ADDED");
|
|
||||||
setMorseCharBuffer(prev => prev + '_')
|
|
||||||
}
|
|
||||||
clearInterval(gapTimer)
|
|
||||||
gapTimer = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInputEnd(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
if (event.keyCode === 188) {
|
|
||||||
leftIsPressed = false
|
|
||||||
|
|
||||||
if (pressedFirst === 'left') { pressedFirst = null }
|
|
||||||
|
|
||||||
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
|
|
||||||
else { stopDepressSyncTimer() }
|
|
||||||
}
|
|
||||||
else if (event.keyCode === 190) {
|
|
||||||
rightIsPressed = false
|
|
||||||
if (pressedFirst === 'right') { pressedFirst = null }
|
|
||||||
|
|
||||||
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
|
|
||||||
else { stopDepressSyncTimer() }
|
|
||||||
}
|
|
||||||
// if (!leftIsPressed && !rightIsPressed ) { startGapTimer() }
|
|
||||||
}
|
|
||||||
|
|
||||||
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(() => {
|
|
||||||
// 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('')
|
|
||||||
}
|
|
||||||
// CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js
|
|
||||||
// else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [morseCharBuffer])
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useElectronicKey
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
import { useContext } from 'react';
|
||||||
import config from '../config.json'
|
import config from '../config.json'
|
||||||
import { WPMContext } from '../contexts/wpmContext.js';
|
import { WPMContext } from '../contexts/wpmContext.js';
|
||||||
import { useContext } from 'react';
|
|
||||||
import { FrequencyContext } from '../contexts/frequencyContext.js';
|
import { FrequencyContext } from '../contexts/frequencyContext.js';
|
||||||
|
|
||||||
function useMorsePlayer() {
|
export default (function useMorsePlayer() {
|
||||||
|
|
||||||
const {wpm} = useContext(WPMContext)
|
const {wpm} = useContext(WPMContext)
|
||||||
const {frequency} = useContext(FrequencyContext)
|
const {frequency} = useContext(FrequencyContext)
|
||||||
|
|
@ -20,13 +20,10 @@ function useMorsePlayer() {
|
||||||
context = null
|
context = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// let frequency = config.frequency
|
// Play dit or dah
|
||||||
|
|
||||||
function play(ditDah) {
|
function play(ditDah) {
|
||||||
let length = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
|
let length = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
|
||||||
// length = 1
|
|
||||||
|
|
||||||
// return new Promise((resolve, reject) => {
|
|
||||||
if (context.state === 'interrupted') {
|
if (context.state === 'interrupted') {
|
||||||
context.resume()
|
context.resume()
|
||||||
}
|
}
|
||||||
|
|
@ -34,9 +31,6 @@ function useMorsePlayer() {
|
||||||
o = context.createOscillator()
|
o = context.createOscillator()
|
||||||
o.frequency.value = frequency
|
o.frequency.value = frequency
|
||||||
o.type = "sine"
|
o.type = "sine"
|
||||||
// o.onended = () => {
|
|
||||||
// resolve()
|
|
||||||
// }
|
|
||||||
|
|
||||||
let startTime = context.currentTime;
|
let startTime = context.currentTime;
|
||||||
|
|
||||||
|
|
@ -47,19 +41,16 @@ function useMorsePlayer() {
|
||||||
g.connect(context.destination)
|
g.connect(context.destination)
|
||||||
o.start(startTime)
|
o.start(startTime)
|
||||||
|
|
||||||
// g.gain.setTargetAtTime(0.0001, startTime + length/1000, 0.001)
|
|
||||||
// o.stop(startTime + length/1000 + 0.05)
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.009)
|
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.009)
|
||||||
o.stop(context.currentTime + 0.05)
|
o.stop(context.currentTime + 0.05)
|
||||||
}, length)
|
}, length)
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let queue = []
|
let queue = []
|
||||||
let timeouts = []
|
let timeouts = []
|
||||||
|
|
||||||
function playMorseWord(morse) {
|
function playMorseWord(morse) {
|
||||||
|
|
||||||
// Empty morse queue and cancel all sounds (timeouts)
|
// Empty morse queue and cancel all sounds (timeouts)
|
||||||
queue = []
|
queue = []
|
||||||
for (let i = 0; i < timeouts.length; i++) {
|
for (let i = 0; i < timeouts.length; i++) {
|
||||||
|
|
@ -67,46 +58,34 @@ function useMorsePlayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
queue = Array.from(morse)
|
queue = Array.from(morse)
|
||||||
// let currentPromise = Promise.resolve();
|
|
||||||
|
|
||||||
let delay = 0
|
let delay = 0
|
||||||
let firstWord = true
|
let firstWord = true
|
||||||
|
|
||||||
|
// Iterate through queue, playing dits/dahs sequentially after appropriate delays
|
||||||
for (let i = 0; i < queue.length; i++) {
|
for (let i = 0; i < queue.length; i++) {
|
||||||
// currentPromise = currentPromise.then(() => {
|
|
||||||
// return playChar(queue[i]);
|
|
||||||
// });
|
|
||||||
|
|
||||||
let char = queue[i]
|
let char = queue[i]
|
||||||
if (char === '.') {
|
if (char === '.') {
|
||||||
if (firstWord) {
|
if (firstWord) {
|
||||||
firstWord = false
|
firstWord = false
|
||||||
// soundQueue.push(
|
timeouts.push(setTimeout(() => {
|
||||||
timeouts.push(setTimeout(() => {
|
play(char)
|
||||||
play(char)
|
}, 0))
|
||||||
}, 0))
|
|
||||||
// )
|
|
||||||
} else {
|
} else {
|
||||||
// soundQueue.push(
|
timeouts.push(setTimeout(() => {
|
||||||
timeouts.push(setTimeout(() => {
|
play(char)
|
||||||
play(char)
|
}, delay))
|
||||||
}, delay))
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
delay += ditMaxTime*2
|
delay += ditMaxTime*2
|
||||||
} else if (char === '-') {
|
} else if (char === '-') {
|
||||||
if (firstWord) {
|
if (firstWord) {
|
||||||
firstWord = false
|
firstWord = false
|
||||||
// soundQueue.push(
|
timeouts.push(setTimeout(() => {
|
||||||
timeouts.push(setTimeout(() => {
|
play(char)
|
||||||
play(char)
|
}, 0))
|
||||||
}, 0))
|
|
||||||
// )
|
|
||||||
} else {
|
} else {
|
||||||
// soundQueue.push(
|
timeouts.push(setTimeout(() => {
|
||||||
timeouts.push(setTimeout(() => {
|
play(char)
|
||||||
play(char)
|
}, delay))
|
||||||
}, delay))
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
delay += ditMaxTime*4
|
delay += ditMaxTime*4
|
||||||
} else if (char === ' ') {
|
} else if (char === ' ') {
|
||||||
|
|
@ -121,28 +100,7 @@ function useMorsePlayer() {
|
||||||
delay += ditMaxTime*6
|
delay += ditMaxTime*6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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 { playMorseWord, play }
|
return { playMorseWord, play }
|
||||||
}
|
})
|
||||||
|
|
||||||
export default useMorsePlayer
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
||||||
setMorseWords(prev => [val, ...prev])
|
|
||||||
|
|
||||||
if (morseWords.length >= morseHistorySize) {
|
|
||||||
setMorseWords(prev => prev.slice(0,prev.length-1))
|
|
||||||
}
|
|
||||||
|
|
||||||
setMorseCharBuffer('')
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [morseCharBuffer])
|
|
||||||
}
|
|
||||||
|
|
||||||
export default usePracticeMode
|
|
||||||
|
|
@ -1,31 +1,30 @@
|
||||||
import {useEffect, useContext} from 'react'
|
import { useEffect, useContext } from 'react'
|
||||||
import {MorseBufferContext} from '../contexts/morseBufferContext'
|
|
||||||
import config from '../config.json'
|
|
||||||
import { WPMContext } from '../contexts/wpmContext'
|
|
||||||
import { GameModeContext } from '../contexts/gameModeContext'
|
|
||||||
import { FrequencyContext } from '../contexts/frequencyContext'
|
import { FrequencyContext } from '../contexts/frequencyContext'
|
||||||
|
import { GameModeContext } from '../contexts/gameModeContext'
|
||||||
|
import { MorseBufferContext } from '../contexts/morseBufferContext'
|
||||||
|
import { WPMContext } from '../contexts/wpmContext'
|
||||||
|
import config from '../config.json'
|
||||||
|
|
||||||
// STRAIGHT KEY TELEGRAPH
|
// STRAIGHT KEY TELEGRAPH
|
||||||
function useStraightKey() {
|
export default (function useStraightKey() {
|
||||||
|
|
||||||
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
|
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
|
||||||
const {wpm} = useContext(WPMContext)
|
const {wpm} = useContext(WPMContext)
|
||||||
const {gameMode} = useContext(GameModeContext)
|
const {gameMode} = useContext(GameModeContext)
|
||||||
const {frequency} = useContext(FrequencyContext)
|
const {frequency} = useContext(FrequencyContext)
|
||||||
|
|
||||||
|
// Spacing time and timer setup
|
||||||
let charTimer = 0
|
let charTimer = 0
|
||||||
let charTime = 0
|
let charTime = 0
|
||||||
let gapTimer = 0
|
let gapTimer = 0
|
||||||
let gapTime = 0
|
let gapTime = 0
|
||||||
|
|
||||||
const timingUnit = config.timingUnit
|
// DitDah Length
|
||||||
|
|
||||||
const ditMaxTime = 1200/wpm * 0.3
|
const ditMaxTime = 1200/wpm * 0.3
|
||||||
|
|
||||||
const letterGapMinTime = ditMaxTime*3
|
const letterGapMinTime = ditMaxTime*3
|
||||||
const wordGapMaxTime = ditMaxTime*7
|
const wordGapMaxTime = ditMaxTime*7
|
||||||
|
|
||||||
const morseHistorySize = config.historySize
|
const morseHistorySize = config.historySize
|
||||||
|
|
||||||
|
|
||||||
// Tone Setup
|
// Tone Setup
|
||||||
let AudioContext = window.AudioContext || window.webkitAudioContext || false
|
let AudioContext = window.AudioContext || window.webkitAudioContext || false
|
||||||
|
|
@ -100,7 +99,7 @@ function useStraightKey() {
|
||||||
// Start Character Timer
|
// Start Character Timer
|
||||||
charTimer = setInterval(() => {
|
charTimer = setInterval(() => {
|
||||||
charTime += 1
|
charTime += 1
|
||||||
}, timingUnit);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInputEnd(event) {
|
function handleInputEnd(event) {
|
||||||
|
|
@ -160,11 +159,11 @@ function useStraightKey() {
|
||||||
gapTimer = 0
|
gapTimer = 0
|
||||||
gapTime = 0
|
gapTime = 0
|
||||||
}
|
}
|
||||||
}, timingUnit);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check gap between letters to determin if new character or new word
|
||||||
function checkGapBetweenInputs() {
|
function checkGapBetweenInputs() {
|
||||||
// Check Gap between letters
|
|
||||||
if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) {
|
if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) {
|
||||||
if (gameMode === 'practice') {
|
if (gameMode === 'practice') {
|
||||||
setMorseCharBuffer(prev => prev + ' ')
|
setMorseCharBuffer(prev => prev + ' ')
|
||||||
|
|
@ -176,19 +175,18 @@ function useStraightKey() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add paddle event listeners and update on WPM, Game Mode, or Frequency change
|
||||||
|
// Not updating on these state changes prevents change from taking effect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.addEventListener('keydown', handleInputStart)
|
document.addEventListener('keydown', handleInputStart)
|
||||||
document.addEventListener('keyup', handleInputEnd)
|
document.addEventListener('keyup', handleInputEnd)
|
||||||
|
|
||||||
const morseButton = document.getElementById('morseButton')
|
const morseButton = document.getElementById('morseButton')
|
||||||
// paddles.forEach(paddle => {
|
morseButton.addEventListener('touchstart', handleInputStart)
|
||||||
morseButton.addEventListener('touchstart', handleInputStart)
|
morseButton.addEventListener('touchend', handleInputEnd)
|
||||||
morseButton.addEventListener('touchend', handleInputEnd)
|
morseButton.addEventListener('mousedown', handleInputStart)
|
||||||
morseButton.addEventListener('mousedown', handleInputStart)
|
morseButton.addEventListener('mouseout', handleInputEnd)
|
||||||
morseButton.addEventListener('mouseout', handleInputEnd)
|
morseButton.addEventListener('mouseup', handleInputEnd)
|
||||||
morseButton.addEventListener('mouseup', handleInputEnd)
|
|
||||||
// })
|
|
||||||
|
|
||||||
return function cleanup() {
|
return function cleanup() {
|
||||||
document.removeEventListener('keydown', handleInputStart)
|
document.removeEventListener('keydown', handleInputStart)
|
||||||
|
|
@ -201,42 +199,30 @@ function useStraightKey() {
|
||||||
morseButton.removeEventListener('mouseout', handleInputEnd)
|
morseButton.removeEventListener('mouseout', handleInputEnd)
|
||||||
morseButton.removeEventListener('mouseup', handleInputEnd)
|
morseButton.removeEventListener('mouseup', handleInputEnd)
|
||||||
|
|
||||||
// const paddles = document.querySelectorAll('.paddle')
|
|
||||||
// paddles.forEach(paddle => {
|
|
||||||
// paddle.removeEventListener('mousedown', handleInputStart)
|
|
||||||
// paddle.removeEventListener('touchstart', handleInputStart)
|
|
||||||
// paddle.removeEventListener('mouseout', handleInputEnd)
|
|
||||||
// paddle.removeEventListener('mouseup', handleInputEnd)
|
|
||||||
// // paddle.removeEventListener('touchend', handleInputEnd)
|
|
||||||
// })
|
|
||||||
|
|
||||||
clearInterval(charTimer)
|
clearInterval(charTimer)
|
||||||
clearInterval(gapTimer)
|
clearInterval(gapTimer)
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [wpm, gameMode, frequency])
|
}, [wpm, gameMode, frequency])
|
||||||
|
|
||||||
|
// Remove forward slash and move buffer contents to morse words array
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// PRACTICE MODE
|
|
||||||
if (morseCharBuffer.slice(-1) === '/' && gameMode === 'practice') {
|
if (morseCharBuffer.slice(-1) === '/' && gameMode === 'practice') {
|
||||||
// Remove forward slash
|
|
||||||
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
|
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
|
||||||
|
|
||||||
setMorseWords(prev => [val, ...prev])
|
setMorseWords(prev => [val, ...prev])
|
||||||
|
|
||||||
|
// Limit history to configured history size
|
||||||
if (morseWords.length >= morseHistorySize) {
|
if (morseWords.length >= morseHistorySize) {
|
||||||
setMorseWords(prev => prev.slice(0,prev.length-1))
|
setMorseWords(prev => prev.slice(0,prev.length-1))
|
||||||
}
|
}
|
||||||
setMorseCharBuffer('')
|
setMorseCharBuffer('')
|
||||||
|
|
||||||
|
// Scroll morse history textbox to bottom (scrolling enabled on mobile screens)
|
||||||
|
let morseHistory = document.getElementById("morseHistory-textbox");
|
||||||
|
morseHistory.scrollTop = morseHistory.scrollHeight;
|
||||||
}
|
}
|
||||||
// CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js
|
|
||||||
// else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [morseCharBuffer])
|
}, [morseCharBuffer])
|
||||||
|
|
||||||
}
|
})
|
||||||
|
|
||||||
export default useStraightKey
|
|
||||||
|
|
@ -2,20 +2,11 @@
|
||||||
$main-font: 'Roboto', sans-serif;
|
$main-font: 'Roboto', sans-serif;
|
||||||
$buffer-font: 'Courier Prime', Courier, monospace;
|
$buffer-font: 'Courier Prime', Courier, monospace;
|
||||||
$ditDah-font: 'Courier', monospace;
|
$ditDah-font: 'Courier', monospace;
|
||||||
|
|
||||||
|
|
||||||
// $main-bg-color-dark: #2c2c2c;
|
|
||||||
// $main-bg-color-light: #f1f1f1;
|
|
||||||
$main-bg-color-light: #eee;
|
$main-bg-color-light: #eee;
|
||||||
$main-font-color-light: #333;
|
$main-font-color-light: #333;
|
||||||
$correct-bg-color: rgba(90,230,90,1);
|
$correct-bg-color: rgba(90,230,90,1);
|
||||||
|
|
||||||
$morseCard-shadow-light: 0px 3px 3px rgba(0, 0, 0, 0.2);
|
|
||||||
$main-box-shadow-light: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px rgba(255, 255, 255, 1);
|
$main-box-shadow-light: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px rgba(255, 255, 255, 1);
|
||||||
$main-box-shadow-light-selected: inset 0px 2px 2px rgba(0, 0, 0, 0.3), inset 0px -1px 1px rgba(255, 255, 255, 1);
|
$main-box-shadow-light-selected: inset 0px 2px 2px rgba(0, 0, 0, 0.3), inset 0px -1px 1px rgba(255, 255, 255, 1);
|
||||||
$main-box-shadow-dark: 0px 3px 3px rgba(0, 0, 0, 0.2), 0px -1px 1px rgba(255, 255, 255, 0.1);
|
|
||||||
$main-box-shadow-dark-selected: inset 0px 2px 2px rgba(0, 0, 0, 0.2), inset 0px -1px 1px rgba(255, 255, 255, 0.1);
|
|
||||||
|
|
||||||
$main-border-radius: 3px;
|
$main-border-radius: 3px;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -32,18 +23,16 @@ button {
|
||||||
}
|
}
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// width: 100%;
|
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
background: $main-bg-color-light;
|
background: $main-bg-color-light;
|
||||||
}
|
}
|
||||||
#root {
|
#root {
|
||||||
|
// border: 3px solid green;
|
||||||
|
width: 100vw;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// width: 100%;
|
|
||||||
width: 100vw;
|
|
||||||
// border: 3px solid green;
|
|
||||||
}
|
}
|
||||||
#header {
|
#header {
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
|
|
@ -66,6 +55,7 @@ html, body {
|
||||||
|
|
||||||
}
|
}
|
||||||
#social-links {
|
#social-links {
|
||||||
|
// border: 1px solid red;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -74,18 +64,15 @@ html, body {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: #999;
|
color: #999;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
// border: 1px solid red;
|
|
||||||
|
|
||||||
i {
|
i {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
&:hover {
|
&:hover {
|
||||||
color: goldenrod;
|
color: gold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// border: 1px solid orange;
|
|
||||||
div {
|
div {
|
||||||
// border: 1px solid red;
|
// border: 1px solid red;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
@ -93,7 +80,6 @@ html, body {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
opacity: 30%;
|
opacity: 30%;
|
||||||
// filter: contrast(100%)
|
|
||||||
&:hover {
|
&:hover {
|
||||||
animation-name: socialLinkHover;
|
animation-name: socialLinkHover;
|
||||||
animation-duration: 150ms;
|
animation-duration: 150ms;
|
||||||
|
|
@ -133,10 +119,8 @@ html, body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
width: 40%;
|
width: 40%;
|
||||||
// width: 40vw;
|
|
||||||
height: calc(100% - 5.1em);
|
height: calc(100% - 5.1em);
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
// min-width: 455px;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
@ -188,7 +172,6 @@ html, body {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 150ms ease-in-out;
|
transition: all 150ms ease-in-out;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
// border-bottom: 2px;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
|
@ -280,15 +263,16 @@ html, body {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
image-rendering: optimizeSpeed;
|
image-rendering: optimizeSpeed;
|
||||||
}
|
}
|
||||||
i:hover {
|
|
||||||
color: goldenrod;
|
|
||||||
}
|
|
||||||
a:visited {
|
a:visited {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
a:hover {
|
a:hover, i:hover {
|
||||||
color: goldenrod;
|
color: goldenrod;
|
||||||
}
|
}
|
||||||
|
i {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,10 +286,10 @@ html, body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 40%;
|
left: 40%;
|
||||||
transition: all 500ms ease-in-out;
|
transition: all 500ms ease-in-out;
|
||||||
|
|
||||||
&.expandLeft {
|
&.expandLeft {
|
||||||
left: 40px;
|
left: 40px;
|
||||||
width: calc(100% - 40px);
|
width: calc(100% - 40px);
|
||||||
|
|
@ -317,8 +301,6 @@ html, body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
||||||
// height: 6em;
|
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
@ -367,7 +349,6 @@ html, body {
|
||||||
#buttons {
|
#buttons {
|
||||||
// border: 1px solid blue;
|
// border: 1px solid blue;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
// margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
#input {
|
#input {
|
||||||
input {
|
input {
|
||||||
|
|
@ -387,7 +368,6 @@ html, body {
|
||||||
height: 1.4em;
|
height: 1.4em;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
// line-height: 10px;
|
|
||||||
i {
|
i {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -6px;
|
left: -6px;
|
||||||
|
|
@ -436,7 +416,6 @@ html, body {
|
||||||
background: #333;
|
background: #333;
|
||||||
font-family: $main-font;
|
font-family: $main-font;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
// font-weight: bold;
|
|
||||||
color: $main-bg-color-light;
|
color: $main-bg-color-light;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|
||||||
|
|
@ -452,7 +431,6 @@ h2 {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
i[class*="ri-"] {
|
i[class*="ri-"] {
|
||||||
// cursor: pointer;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: #777;
|
color: #777;
|
||||||
|
|
@ -469,10 +447,7 @@ i[class*="ri-"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// justify-content: center;
|
|
||||||
margin-bottom: 45px;
|
margin-bottom: 45px;
|
||||||
// overflow: hidden;
|
|
||||||
|
|
||||||
|
|
||||||
#input {
|
#input {
|
||||||
// border: 1px solid red;
|
// border: 1px solid red;
|
||||||
|
|
@ -528,25 +503,12 @@ i[class*="ri-"] {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
// &#letters .item {
|
|
||||||
// width: 17%;
|
|
||||||
// }
|
|
||||||
// &#numbers .item {
|
|
||||||
// width: 18%;
|
|
||||||
// }
|
|
||||||
// &#special .item {
|
|
||||||
// width: 20%;
|
|
||||||
// }
|
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
font-family: $ditDah-font;
|
font-family: $ditDah-font;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
// height: 2em;
|
|
||||||
// height: 2em;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// justify-content: space-between;
|
|
||||||
width: 15%;
|
width: 15%;
|
||||||
|
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
|
@ -577,19 +539,6 @@ i[class*="ri-"] {
|
||||||
background: rgba(112, 128, 144,0.6);
|
background: rgba(112, 128, 144,0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// button {
|
|
||||||
// width: 20px;
|
|
||||||
// height: 20px;
|
|
||||||
// margin: 4px;
|
|
||||||
// border: 0px;
|
|
||||||
// border-radius: 2px;
|
|
||||||
// box-shadow: $main-box-shadow-light;
|
|
||||||
// &:active {
|
|
||||||
// transform: translateY(3px);
|
|
||||||
// box-shadow: 0px 0px 2px rgba(0,0,0,0.3);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
span:first-child {
|
span:first-child {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -617,8 +566,8 @@ i[class*="ri-"] {
|
||||||
$button-diameter: 100px;
|
$button-diameter: 100px;
|
||||||
$button-radius: 50px;
|
$button-radius: 50px;
|
||||||
$morse-button-color: rgba(112, 138, 144,0.5);
|
$morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
#morseButton {
|
|
||||||
|
|
||||||
|
#morseButton {
|
||||||
width: $button-diameter;
|
width: $button-diameter;
|
||||||
height: $button-diameter;
|
height: $button-diameter;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
|
|
@ -636,9 +585,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
transform: translateY(3px);
|
transform: translateY(3px);
|
||||||
box-shadow: 0px 0px 2px rgba(0,0,0,0.3);
|
box-shadow: 0px 0px 2px rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
// &:active > button, &.active > button {
|
|
||||||
// transform: translateY(1px);
|
|
||||||
// }
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
@ -648,7 +594,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
background: $morse-button-color;
|
background: $morse-button-color;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border: 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;
|
transition: transform 40ms ease-out, box-shadow 40ms ease-out, width 500ms ease-out, background 500ms ease-out, color 500ms ease-out;
|
||||||
|
|
||||||
&.showPaddles {
|
&.showPaddles {
|
||||||
|
|
@ -659,11 +604,11 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
box-shadow: $main-box-shadow-light;
|
box-shadow: $main-box-shadow-light;
|
||||||
}
|
}
|
||||||
&#left {
|
&#left {
|
||||||
|
// background: red;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
border-radius: $button-radius 0px 0px $button-radius;
|
border-radius: $button-radius 0px 0px $button-radius;
|
||||||
// transition: all 500ms ease-out;
|
|
||||||
display: none;
|
display: none;
|
||||||
// background: red;
|
|
||||||
&.showPaddles{
|
&.showPaddles{
|
||||||
border-radius: $button-radius 0 0 $button-radius;
|
border-radius: $button-radius 0 0 $button-radius;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -672,11 +617,11 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&#right {
|
&#right {
|
||||||
|
// background: blue;
|
||||||
border-radius: 0 $button-radius $button-radius 0;
|
border-radius: 0 $button-radius $button-radius 0;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
// transition: all 500ms ease-out;
|
|
||||||
display: none;
|
display: none;
|
||||||
// background: blue;
|
|
||||||
&.showPaddles{
|
&.showPaddles{
|
||||||
border-radius: 0 $button-radius $button-radius 0;
|
border-radius: 0 $button-radius $button-radius 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -698,6 +643,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#morseButtonText {
|
#morseButtonText {
|
||||||
|
font-family: $main-font;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
|
@ -725,26 +671,18 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
// background-color: rgba(0,0,0,0.4);
|
|
||||||
background: rgba(255,255,255,0.75);
|
background: rgba(255,255,255,0.75);
|
||||||
// background-image: linear-gradient(0deg, transparent, rgba(1,1,1,1));
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
// align-items: center;
|
|
||||||
|
|
||||||
|
|
||||||
&.fade {
|
&.fade {
|
||||||
// animation: hideOverlay 2000ms 1 ease-out forwards;
|
|
||||||
animation: hideOverlay 1s ease-out forwards;
|
animation: hideOverlay 1s ease-out forwards;
|
||||||
}
|
}
|
||||||
&.hide {
|
&.hide {
|
||||||
// animation: hideOverlay 2000ms 1 ease-out forwards;
|
|
||||||
z-index: -100;
|
z-index: -100;
|
||||||
}
|
}
|
||||||
|
|
||||||
#challengeReady, #challengeComplete {
|
#challengeReady, #challengeComplete {
|
||||||
position: relative;
|
position: relative;
|
||||||
// width: 400px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|
@ -755,7 +693,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
padding: 1.7em;
|
padding: 1.7em;
|
||||||
height: 35%;
|
height: 35%;
|
||||||
background: $main-bg-color-light;
|
background: $main-bg-color-light;
|
||||||
// background: #fefefe;
|
|
||||||
margin-top: 10rem;
|
margin-top: 10rem;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0px 5px 15px rgba(0,0,0,0.5);
|
box-shadow: 0px 5px 15px rgba(0,0,0,0.5);
|
||||||
|
|
@ -788,7 +725,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
|
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
color: $main-font-color-light;
|
color: $main-font-color-light;
|
||||||
// max-width: 250px;
|
|
||||||
&#startChallenge, &#continue {
|
&#startChallenge, &#continue {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 1.7em;
|
font-size: 1.7em;
|
||||||
|
|
@ -799,9 +736,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.3rem;
|
letter-spacing: 0.3rem;
|
||||||
|
|
||||||
// &:hover {
|
|
||||||
// text-shadow: 0px 0px 7px rgba(255,255,255,0.3);
|
|
||||||
// }
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: translateY(3px);
|
transform: translateY(3px);
|
||||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
|
|
@ -836,7 +770,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// width: 40%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
@ -851,12 +784,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
// &:hover {
|
|
||||||
// color: goldenrod;
|
|
||||||
// }
|
|
||||||
// &:active {
|
|
||||||
// box-shadow: $main-box-shadow-light-selected;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div#info {
|
div#info {
|
||||||
|
|
@ -909,6 +836,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#challengeWord {
|
#challengeWord {
|
||||||
|
// border: 1px solid green;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -921,7 +849,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
|
|
||||||
// border: 1px solid green;
|
|
||||||
border-radius: $main-border-radius;
|
border-radius: $main-border-radius;
|
||||||
box-shadow: $main-box-shadow-light;
|
box-shadow: $main-box-shadow-light;
|
||||||
|
|
||||||
|
|
@ -951,18 +878,11 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
}
|
}
|
||||||
&.correct {
|
&.correct {
|
||||||
background: $correct-bg-color;
|
background: $correct-bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#tip {
|
|
||||||
font-size: 2rem;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#morseBufferDisplay {
|
#morseBufferDisplay {
|
||||||
// border: 1px solid green;
|
// border: 1px solid green;
|
||||||
// background: #eee;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
|
|
@ -972,8 +892,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
font-family: $buffer-font;
|
font-family: $buffer-font;
|
||||||
position: relative;
|
position: relative;
|
||||||
// box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
|
||||||
// border-bottom: 2px solid rgba(0,0,0,0.1);
|
|
||||||
|
|
||||||
#overlay {
|
#overlay {
|
||||||
// background: blue;
|
// background: blue;
|
||||||
|
|
@ -989,8 +907,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
|
|
||||||
#alphanumeric-container {
|
#alphanumeric-container {
|
||||||
// border: 1px solid red;
|
// border: 1px solid red;
|
||||||
// max-width: 100%;
|
|
||||||
// min-width: 300px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -1033,7 +949,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
width: 30px !important;
|
width: 30px !important;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
border-radius: $main-border-radius;
|
border-radius: $main-border-radius;
|
||||||
box-shadow: $main-box-shadow-dark;
|
box-shadow: $main-box-shadow-light;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1078,7 +994,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
height: 40px;
|
height: 40px;
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
border-radius: $main-border-radius;
|
border-radius: $main-border-radius;
|
||||||
box-shadow: $main-box-shadow-dark;
|
box-shadow: $main-box-shadow-light;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1091,16 +1007,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
.space {
|
.space {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
.strike {
|
|
||||||
text-decoration: line-through;
|
|
||||||
opacity: 30%;
|
|
||||||
}
|
|
||||||
.morseError {
|
|
||||||
background: rgba(255,0,0,0.4);
|
|
||||||
color: rgb(120, 0, 0);
|
|
||||||
border-radius: $main-border-radius;
|
|
||||||
// text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
#morse-history {
|
#morse-history {
|
||||||
// border: 1px solid blue;
|
// border: 1px solid blue;
|
||||||
|
|
@ -1133,7 +1039,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
border-radius: $main-border-radius;
|
border-radius: $main-border-radius;
|
||||||
box-shadow: $main-box-shadow-dark;
|
box-shadow: $main-box-shadow-light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#clear {
|
#clear {
|
||||||
|
|
@ -1142,6 +1048,7 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
#message {
|
#message {
|
||||||
|
font-family: $main-font;
|
||||||
padding: 0.3em;
|
padding: 0.3em;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
color: #777;
|
color: #777;
|
||||||
|
|
@ -1155,11 +1062,9 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
// border-radius: 3px;
|
|
||||||
padding: 0.7em;
|
padding: 0.7em;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// text-transform: uppercase;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: maroon;
|
color: maroon;
|
||||||
}
|
}
|
||||||
|
|
@ -1189,99 +1094,23 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.morseCard {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row !important;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
font-size: 1.6rem;
|
|
||||||
font-family: $buffer-font;
|
|
||||||
|
|
||||||
.ditDahs-container, .alphanumeric-container {
|
|
||||||
// border: 1px solid green;
|
|
||||||
display: flex;
|
|
||||||
width: 50%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.alphanumeric-container span {
|
|
||||||
// background: blue;
|
|
||||||
padding-top: 0.17em;
|
|
||||||
}
|
|
||||||
.ditDahs-container {
|
|
||||||
// border: 1px solid red;
|
|
||||||
justify-content: flex-end;
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div div {
|
|
||||||
// border: 1px solid cyan;
|
|
||||||
padding: 3px;
|
|
||||||
margin: 2px;
|
|
||||||
background: #fdfdfd;
|
|
||||||
white-space: nowrap;
|
|
||||||
border-radius: $main-border-radius;
|
|
||||||
box-shadow: $morseCard-shadow-light;
|
|
||||||
line-height: 1em;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
span.morseError {
|
|
||||||
background: rgba(255,0,0,0.4);
|
|
||||||
height: 1.7rem;
|
|
||||||
color: rgb(120, 0, 0);
|
|
||||||
border-radius: $main-border-radius;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ditDahs {
|
|
||||||
// border: 1px solid red;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
font-family: $ditDah-font;
|
|
||||||
font-weight: bold;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
span.space {
|
|
||||||
border-radius: $main-border-radius;
|
|
||||||
background: $main-bg-color-light;
|
|
||||||
opacity: 0.5;
|
|
||||||
width: 3px;
|
|
||||||
margin-left: 4px;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// @media screen and (max-width: 415px) {
|
|
||||||
@media only screen and (max-width: 1024px) {
|
@media only screen and (max-width: 1024px) {
|
||||||
#root {
|
|
||||||
#main-content {
|
#sidebar-content {
|
||||||
.sidebar#left {
|
#info {
|
||||||
#sidebar-container{
|
padding: 1em;
|
||||||
#sidebar-content {
|
}
|
||||||
#info {
|
#playerAndLegend {
|
||||||
padding: 1em;
|
padding: 0;
|
||||||
}
|
#legend #legend-items button {
|
||||||
#playerAndLegend {
|
width: 20%;
|
||||||
padding: 0;
|
|
||||||
#legend #legend-items button {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#main-interface {
|
|
||||||
#mainOptions {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#mainOptions {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 415px) {
|
@media only screen and (max-width: 415px) {
|
||||||
|
|
||||||
|
|
@ -1450,9 +1279,6 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
min-width: 1.7rem;
|
min-width: 1.7rem;
|
||||||
max-width: 1.7rem;
|
max-width: 1.7rem;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
// font-size: 1rem;
|
|
||||||
// height: 1em;
|
|
||||||
// width: 0.7em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1460,12 +1286,18 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
#morse-history {
|
#morse-history {
|
||||||
// border: 2px solid cyan;
|
// border: 2px solid cyan;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
|
|
||||||
#morseHistory-textbox {
|
#morseHistory-textbox {
|
||||||
// border: 2px solid cyan;
|
// border: 2px solid cyan;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
max-height: 2em;
|
max-height: 2em;
|
||||||
}
|
}
|
||||||
|
#clear button {
|
||||||
|
padding: 0px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#challenge-header {
|
#challenge-header {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
@ -1486,6 +1318,10 @@ $morse-button-color: rgba(112, 138, 144,0.5);
|
||||||
// font-size: 2.3rem;
|
// font-size: 2.3rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#morseButton {
|
||||||
|
margin-top: 0;
|
||||||
|
transform: scale(0.85);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue