Initial commit

This commit is contained in:
Gene Mecija 2019-12-21 14:48:36 -08:00
parent 482002d111
commit b11506f6de
11 changed files with 471 additions and 49 deletions

View file

@ -1,38 +1,122 @@
.App {
text-align: center;
html, body {
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
}
#root {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
}
#root div {
width: 95vw;
}
.App-logo {
height: 40vmin;
pointer-events: none;
#morseButton {
width: 200px !important;
height: 200px;
background: goldenrod;
border-radius: 100px;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
#morseBufferDisplay {
display: flex;
justify-content: center;
/* border: 1px solid green; */
width: 100%;
height: 40px;
}
/* #morseBufferDisplay div {
width: 50% !important;
border: 1px dotted orange;
} */
#morseBufferDisplay #ditDahs {
width: 50%;
padding-right: 5px;
border-right: 2px solid #000;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.ditDah {
background: #DDD;
height: 40px;
width: 30px !important;
margin-left: 3px;
box-shadow: 0px 1px 0px #000;
display: flex;
justify-content: center;
align-items: center;
font-size: 35px;
font-family: 'Courier';
font-weight: bold;
}
.space {
font-size: 20px;
}
.morseError {
background: rgba(255,0,0,0.4);
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
#morseBufferDisplay #alphanumeric {
padding-left: 5px;
border-left: 2px solid #000;
width: 50%;
font-size: 40px;
font-family: 'Courier';
font-weight: bold;
}
.App-link {
color: #61dafb;
#morseDisplay {
/* border: 2px solid red; */
display: flex;
flex-direction: row;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
#cardContainer div .morseCard:nth-child(1){
opacity: 100%;
}
#cardContainer div .morseCard:nth-child(2){
opacity: 70%;
}
#cardContainer div .morseCard:nth-child(3){
opacity: 50%;
}
#cardContainer div .morseCard:nth-child(4){
opacity: 30%;
}
#cardContainer div .morseCard:nth-child(5){
opacity: 10%;
}
.morseCard {
display: flex;
flex-direction: row !important;
justify-content: center;
/* border: 1px solid blue; */
margin-bottom: 2px;
font-size: 40px;
font-family: 'Courier';
font-weight: bold;
}
.morseCard div {
/* border: 1px solid green; */
padding: 5px;
margin: 2px;
/* border: 1px solid #EEE; */
background: #EEE;
/* box-shadow: 0px 2px 2px -2px #666; */
}
.morseCard .ditDahs {
display: flex;
justify-content: flex-end;
}
/* #morseBufferDisplay {
border: 1px solid green;
}
#morseDisplay #cardContainer div {
display: flex;
flex-direction: column;
flex-grow: 1;
} */

View file

@ -1,26 +1,149 @@
import React from 'react';
import logo from './logo.svg';
import React, { useEffect, useState } from 'react';
import './App.css';
import MorseDisplay from './components/MorseDisplay'
import MorseBufferDisplay from './components/MorseBufferDisplay'
import MorseButton from './components/MorseButton'
// import LettersDisplay from './components/LettersDisplay'
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..'
// const [morseLettersBuffer, setMorseLettersBuffer] = useState([]) // e.g. ['-..','.','-,']
const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']]
let charTimer = 0
let charTime = 0
let gapTimer = 0
let gapTime = 0
const timingUnit = 15 // default: 25
const ditMaxTime = 5 // default: 3
const letterGapMinTime = ditMaxTime*3
const wordGapMaxTime = ditMaxTime*7
const morseHistorySize = 3
let context = new AudioContext()
let o
function handleInputStart(event) {
if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
(event.repeat)) {
return
}
// if (gapTimer===0) { setMorseLettersBuffer('') }
checkGapBetweenInputs()
clearInterval(gapTimer)
o = context.createOscillator()
o.type = "sine"
let frequency = 550.0
o.frequency.value = frequency
o.connect(context.destination)
o.start()
startCharTimer()
}
function startCharTimer() {
// Reset character time
charTime = 0
// Start Character Timer
charTimer = setInterval(() => {
charTime += 1
}, timingUnit);
}
function handleInputEnd(event) {
if ((event.keyCode !== 32 && event.target.id !== "morseButton") ||
(event.repeat)) {
return
}
if (charTime <= ditMaxTime) {
setMorseCharBuffer(prev => prev + '.')
} else {
setMorseCharBuffer(prev => prev + '-')
}
stopCharTimer()
startGapTimer()
o.stop()
}
function stopCharTimer() {
clearInterval(charTimer)
charTimer = 0
}
function startGapTimer() {
gapTime = 0
gapTimer = setInterval(() => {
gapTime += 1
// Gap between words
if (gapTime >= wordGapMaxTime) {
setMorseCharBuffer(prev => prev + '/')
clearInterval(gapTimer)
gapTimer = 0
gapTime = 0
}
}, timingUnit);
}
function checkGapBetweenInputs() {
// Check Gap between letters
if ((gapTime >= letterGapMinTime) && (gapTime < wordGapMaxTime)) {
// setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
setMorseCharBuffer(prev => prev + ' ')
// morseLettersBuffer = [...morseLettersBuffer, morseCharBuffer]
// setMorseCharBuffer('')
clearInterval(gapTimer)
gapTimer = 0
}
}
useEffect(() => {
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
document.getElementById('morseButton').addEventListener('mousedown', handleInputStart)
document.getElementById('morseButton').addEventListener('mouseup', handleInputEnd)
// eslint-disable-next-line
}, [])
useEffect(() => {
if (morseCharBuffer.slice(-1) === ' ') {
// setMorseLettersBuffer([morseCharBuffer])
// setMorseCharBuffer('')
}
if (morseCharBuffer.slice(-1) === '/') {
// Remove forward slash
let val = morseCharBuffer.slice(0,morseCharBuffer.length-1)
console.log('val: ', val);
setMorseWords(prev => [val, ...prev])
if (morseWords.length >= morseHistorySize) {
setMorseWords(prev => prev.slice(0,prev.length-1))
}
setMorseCharBuffer('')
}
// setMorseLettersBuffer(prev => [...prev, morseCharBuffer])
// eslint-disable-next-line
}, [morseCharBuffer])
return (
<div>charTime: {charTime}<br/>
<MorseButton />
morseCharBuffer:<br/>
<MorseBufferDisplay buffer={morseCharBuffer} /><br/>
<MorseDisplay morseWords={morseWords}/>
</div>
);
}
export default App;

4
src/MorseCard.css Normal file
View file

@ -0,0 +1,4 @@
.morseCard {
border: 1px solid blue;
margin-bottom: 2px;
}

View file

@ -0,0 +1,23 @@
import React from "react"
import morseCode from '../data/morse-reverse.json'
function AlphaNumeric(props) {
if (props.morseLetter === '') {
return (
<span></span>
)
} else {
if (morseCode[props.morseLetter] === undefined) {
return (
<span className='morseError'>[?]</span>
)
} else {
return (
<span>{morseCode[props.morseLetter].toUpperCase()}</span>
)
}
}
}
export default AlphaNumeric

23
src/components/DitDah.js Normal file
View file

@ -0,0 +1,23 @@
import React from "react"
import morseCode from '../data/morse-reverse.json'
function DitDah(props) {
if (props.morseLetter === '') {
return (
<span className='space'>&nbsp;</span>
)
} else {
if (morseCode[props.morseLetter] === undefined) {
return (
<span className='morseError'>{props.morseLetter}</span>
)
} else {
return (
<span>{props.morseLetter}</span>
)
}
}
}
export default DitDah

View file

@ -0,0 +1,12 @@
import React from "react"
function DitDahDisplay(props) {
return (
<div className='ditDah'>
{props.dd}
</div>
)
}
export default DitDahDisplay

View file

@ -0,0 +1,44 @@
import React from "react"
import DitDahDisplay from "./DitDahDisplay"
import morseCode from '../data/morse-reverse.json'
function MorseBufferDisplay(props) {
let ditDahs = props.buffer.split('').map((ditdah,index) => <DitDahDisplay key={index} dd={ditdah} />)
let alphanumeric = ''
if (props.buffer.includes(' ')) {
let letters = props.buffer.split(' ')
for (let i in letters) {
if (letters[i] === ' ') {
alphanumeric += ' '
} else {
if (morseCode[letters[i]] === undefined) {
// alphanumeric += '[?]'
} else {
alphanumeric += morseCode[letters[i]]
}
}
}
} else if (props.buffer !== '') {
let letters = props.buffer
if (morseCode[letters] === undefined) {
alphanumeric += '[?]'
} else {
alphanumeric += morseCode[letters]
}
}
return (
<div id="morseBufferDisplay">
<div id="ditDahs">
{ditDahs}
</div>
<div id="alphanumeric">
{alphanumeric.toUpperCase()}
</div>
</div>
)
}
export default MorseBufferDisplay

View file

@ -0,0 +1,10 @@
import React from "react"
function MorseButton() {
return (
<div id="morseButton"></div>
)
}
export default MorseButton

View file

@ -0,0 +1,35 @@
import React from "react"
import AlphaNumeric from './AlphaNumeric'
import DitDah from './DitDah'
function MorseCard(props) {
let morseComponent
let alphaNumericsComponent
if (props.morse.includes(' ')) {
let letters = props.morse.split(' ').join(' ').split(' ')
morseComponent = letters.map((letter, index) => <DitDah key={index} morseLetter={letter}/>)
alphaNumericsComponent = letters.map((letter, index) => <AlphaNumeric key={index} morseLetter={letter}/>)
}
else {
let letter = props.morse
morseComponent = <DitDah morseLetter={letter} />
alphaNumericsComponent = <AlphaNumeric morseLetter={letter} />
}
return (
<div className='morseCard'>
<div className='ditDahs'>
{morseComponent}
</div>
<div className='alphanumeric'>
{alphaNumericsComponent}
</div>
</div>
)
}
export default MorseCard

View file

@ -0,0 +1,17 @@
import React from "react"
import MorseCard from './MorseCard'
function MorseDisplay(props) {
let morseCards = props.morseWords.map((word,index) => <MorseCard key={index} morse={word} />)
return (
<div id="morseDisplay">
<div id="cardContainer">
<div>{morseCards}</div>
</div>
</div>
)
}
export default MorseDisplay

View file

@ -0,0 +1,47 @@
{
"-----": "0",
".----": "1",
"..---": "2",
"...--": "3",
"....-": "4",
".....": "5",
"-....": "6",
"--...": "7",
"---..": "8",
"----.": "9",
".-": "a",
"-...": "b",
"-.-.": "c",
"-..": "d",
".": "e",
"..-.": "f",
"--.": "g",
"....": "h",
"..": "i",
".---": "j",
"-.-": "k",
".-..": "l",
"--": "m",
"-.": "n",
"---": "o",
".--.": "p",
"--.-": "q",
".-.": "r",
"...": "s",
"-": "t",
"..-": "u",
"...-": "v",
".--": "w",
"-..-": "x",
"-.--": "y",
"--..": "z",
".-.-.-": ".",
"--..--": ",",
"..--..": "?",
"-.-.--": "!",
"-....-": "-",
"-..-.": "/",
".--.-.": "@",
"-.--.": "(",
"-.--.-": ")"
}