mirror of
https://github.com/genemecija/learn-morse-code.git
synced 2026-01-04 07:39:59 +01:00
Challenge mode functionality complete; layout updates
This commit is contained in:
parent
dd077e6d12
commit
113e4a2348
|
|
@ -40,8 +40,8 @@ export default React.memo(function App() {
|
|||
<MorseBufferContextProvider>
|
||||
<WordListPickerContextProvider>
|
||||
<WordFeederContextProvider>
|
||||
<GameClockContextProvider>
|
||||
<ChallengeContextProvider>
|
||||
<GameClockContextProvider>
|
||||
<SidebarLeft />
|
||||
<div id="main-interface">
|
||||
<div id="mainOptions">
|
||||
|
|
@ -82,8 +82,8 @@ export default React.memo(function App() {
|
|||
<div id="settings-icon" onClick={toggleRight}><i class="ri-settings-3-line"></i></div>
|
||||
|
||||
</div> */}
|
||||
</ChallengeContextProvider>
|
||||
</GameClockContextProvider>
|
||||
</ChallengeContextProvider>
|
||||
</WordFeederContextProvider>
|
||||
</WordListPickerContextProvider>
|
||||
</MorseBufferContextProvider>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import React, {useContext} from 'react';
|
||||
import '../css/App.css';
|
||||
import morseCode from '../data/morse-reverse.json'
|
||||
import ChallengeWord from '../components/ChallengeWord'
|
||||
import ChallengeBufferDisplay from '../components/ChallengeBufferDisplay';
|
||||
import { MorseBufferContext } from '../contexts/morseBufferContext';
|
||||
import { WordFeederContext } from '../contexts/wordFeederContext';
|
||||
import GameClock from '../components/GameClock';
|
||||
import { GameClockContext } from '../contexts/gameClockContext';
|
||||
import { KeyTypeContext } from '../contexts/keyTypeContext';
|
||||
import StraightKey from '../components/StraightKey';
|
||||
import ElectronicKey from '../components/ElectronicKey';
|
||||
|
|
@ -14,102 +10,21 @@ import ChallengeControls from '../components/ChallengeControls';
|
|||
import { ChallengeContext } from '../contexts/challengeContext';
|
||||
|
||||
|
||||
export default React.memo(function ChallengeMode(props) {
|
||||
|
||||
console.log('CHALLENGE MODE');
|
||||
const {word, getNextWord} = useContext(WordFeederContext)
|
||||
const {clockIsRunning} = useContext(GameClockContext)
|
||||
const {morseCharBuffer, setMorseCharBuffer} = useContext(MorseBufferContext)
|
||||
export default React.memo(function ChallengeMode() {
|
||||
|
||||
const {keyType} = useContext(KeyTypeContext)
|
||||
const {completeChallenge, cancelChallenge} = useContext(ChallengeContext)
|
||||
|
||||
let morseArray = morseCharBuffer.split('_').filter(l => l !== '')
|
||||
let challengeWordClass = ''
|
||||
|
||||
let correctCharIndexes = [] // Indexes of correct letters in Challenge Word
|
||||
let incorrectMorseIndexes = [] // Indexes of incorrect morse characters in morse character buffer
|
||||
|
||||
let offset = 0
|
||||
let challengeLetters
|
||||
|
||||
// If no more words in wordlist, feeder returns first word in an array
|
||||
if (typeof word === 'object') {
|
||||
completeChallenge()
|
||||
challengeLetters = word[0].split('')
|
||||
}
|
||||
else {
|
||||
challengeLetters = word.split('')
|
||||
}
|
||||
|
||||
// Iterate through the morse character buffer and compare with each letter of challenge word
|
||||
morseArray.forEach((item, index) => {
|
||||
if (morseCharBuffer.slice(-1) === '_') { // If end of morse character
|
||||
|
||||
let morseLetter = morseCode[morseArray[index]] || '[?]'
|
||||
let challengeLetter = challengeLetters[index-offset].toLowerCase()
|
||||
|
||||
if (morseLetter === challengeLetter) {
|
||||
correctCharIndexes.push(index-offset)
|
||||
|
||||
document.getElementById('challengeWord').childNodes[index-offset].classList.add('correct')
|
||||
// incorrectCharIndex = null
|
||||
}
|
||||
else {
|
||||
// incorrectCharIndex = index-offset
|
||||
incorrectMorseIndexes.push(index)
|
||||
if (incorrectMorseIndexes.length > 0) {
|
||||
setMorseCharBuffer(prev => {
|
||||
let newState = prev.split('_').filter(l => l !== '')
|
||||
newState.splice(incorrectMorseIndexes[0], 1)
|
||||
newState = newState.join('_') + '_'
|
||||
|
||||
return newState
|
||||
})
|
||||
incorrectMorseIndexes.splice(1,incorrectMorseIndexes.length)
|
||||
}
|
||||
offset = incorrectMorseIndexes.length
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function timeout(delay) {
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, delay)
|
||||
})
|
||||
}
|
||||
|
||||
// Next word once all correct
|
||||
if (correctCharIndexes.length === challengeLetters.length) {
|
||||
//
|
||||
challengeWordClass = 'correct'
|
||||
setTimeout(() => {
|
||||
setMorseCharBuffer('')
|
||||
morseArray = []
|
||||
incorrectMorseIndexes = []
|
||||
correctCharIndexes = []
|
||||
offset = 0
|
||||
}, 800)
|
||||
setTimeout(() => {
|
||||
getNextWord()
|
||||
if (document.getElementById('challengeWord') !== null) {
|
||||
document.getElementById('challengeWord').childNodes.forEach(node => {
|
||||
node.classList = "cLetter"
|
||||
})
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const {challengeState, cancelChallenge, morseArray, incorrectMorseIndexes, challengeWordClass} = useContext(ChallengeContext)
|
||||
|
||||
return (
|
||||
<>
|
||||
{clockIsRunning ? (keyType === "straight" ?
|
||||
{challengeState === 'started' ? (keyType === "straight" ?
|
||||
<StraightKey /> : <ElectronicKey />) : <></>
|
||||
}
|
||||
<ChallengeControls cancelChallenge={cancelChallenge} />
|
||||
<GameClock />
|
||||
<ChallengeWord className={challengeWordClass} word={word} />
|
||||
<div id="challenge-header">
|
||||
<GameClock />
|
||||
<ChallengeControls cancelChallenge={cancelChallenge} />
|
||||
</div>
|
||||
<ChallengeWord challengeWordClass={challengeWordClass} />
|
||||
<ChallengeBufferDisplay morseArray={morseArray} incorrectMorseIndexes={incorrectMorseIndexes} />
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ import { ChallengeContext } from "../contexts/challengeContext"
|
|||
export default (function ChallengeComplete(props) {
|
||||
|
||||
const {gameClockTime} = useContext(GameClockContext)
|
||||
const {cancelChallenge} = useContext(ChallengeContext)
|
||||
const {setChallengeState} = useContext(ChallengeContext)
|
||||
|
||||
function _continue() {
|
||||
// setGameClockTime(0)
|
||||
// props.setChallengeState('ready')
|
||||
cancelChallenge()
|
||||
setChallengeState('ready')
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="challengeComplete" className="notify">
|
||||
<h2>Challenge Complete</h2>
|
||||
Challenge completed in {gameClockTime} seconds!
|
||||
<span id="notify-title">Challenge Complete</span>
|
||||
<span id="message">Challenge completed in {gameClockTime} seconds!</span>
|
||||
<button id="continue" onClick={_continue}>Continue</button>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export default (function ChallengeControls(props) {
|
|||
|
||||
return (
|
||||
<div id="challengeControls">
|
||||
<button onClick={props.cancelChallenge}>Exit</button>
|
||||
<button onClick={props.cancelChallenge}>Exit Challenge</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
@ -8,7 +8,7 @@ export default (function ChallengeReady() {
|
|||
|
||||
return (
|
||||
<div id="challengeReady" className="notify">
|
||||
<h2>Challenge Options</h2>
|
||||
<span id="notify-title">Challenge Options</span>
|
||||
<WordListPicker />
|
||||
<button id="startChallenge" onClick={startChallenge}>Start Challenge</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useContext } from "react"
|
||||
import { WordFeederContext } from "../contexts/wordFeederContext"
|
||||
import { ChallengeContext } from "../contexts/challengeContext"
|
||||
|
||||
export default React.memo(function ChallengeWord(props) {
|
||||
|
||||
let challengeWordClass= props.className
|
||||
const {word} = useContext(WordFeederContext)
|
||||
|
||||
let challengeLetters
|
||||
|
|
@ -21,6 +21,6 @@ export default React.memo(function ChallengeWord(props) {
|
|||
})
|
||||
|
||||
return (
|
||||
<div id="challengeWord" className={challengeWordClass}>{spannedWord}</div>
|
||||
<div id="challengeWord" className={props.challengeWordClass}>{spannedWord}</div>
|
||||
)
|
||||
})
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
import React, {useContext} from "react"
|
||||
import { GameClockContext } from "../contexts/gameClockContext";
|
||||
|
||||
function GameClock(props) {
|
||||
export default (function GameClock(props) {
|
||||
|
||||
const {gameClockTime} = useContext(GameClockContext)
|
||||
|
||||
return (
|
||||
<div id="gameClock">{gameClockTime}</div>
|
||||
)
|
||||
}
|
||||
const minutes = Math.floor(gameClockTime / 60)
|
||||
const seconds = gameClockTime % 60
|
||||
|
||||
export default GameClock
|
||||
return (
|
||||
<div id="gameClock">Time Elapsed: <span id="clockTime">{minutes} minutes {seconds} seconds</span></div>
|
||||
)
|
||||
})
|
||||
|
|
@ -16,20 +16,15 @@ export default React.memo(function Info() {
|
|||
|
||||
<h2>Dits and Dahs</h2>
|
||||
<p>
|
||||
<span className="bold">Dit</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('.')}></i><br />
|
||||
Denoted as a dot (.), dits are short tones and are base unit of morse code.<br />
|
||||
<span className="bold">Dah</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('-')}></i><br />
|
||||
Denoted as a dash (-), dahs are long tones the length of three dits.
|
||||
<span className="bold">Dit</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('.')}></i> Denoted as a dot (.), dits are short tones and are base unit of morse code.<br />
|
||||
<span className="bold">Dah</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('-')}></i> Denoted as a dash (-), dahs are long tones the length of three dits.
|
||||
</p>
|
||||
|
||||
<h2>Spacing</h2 >
|
||||
<p>
|
||||
<span className="bold">Intra-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i><br />
|
||||
Silence between dits and dahs the length of one dit. Three dits separated by one-dit-long spaces is an "S".<br />
|
||||
<span className="bold">Inter-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('. . .')}></i><br />
|
||||
Silence the length of three dits. Three dits separated by three-dit-long spaces is "EEE".<br />
|
||||
<span className="bold">Inter-word Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('. /. /.')}></i><br />
|
||||
Silence the length of seven dits. Three dits separated by seven-dit-long spaces is "E E E".
|
||||
<span className="bold">Intra-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('...')}></i> Silence between dits and dahs the length of one dit. Three dits separated by one-dit-long spaces is an "S".<br />
|
||||
<span className="bold">Inter-character Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('. . .')}></i> Silence the length of three dits. Three dits separated by three-dit-long spaces is "EEE".<br />
|
||||
<span className="bold">Inter-word Spacing</span> <i className="ri-volume-up-fill" onClick={() => playMorseWord('././.')}></i> Silence the length of seven dits. Three dits separated by seven-dit-long spaces is "E E E".
|
||||
</p>
|
||||
|
||||
<h2>Speed</h2>
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ export default (function MorseHistoryTextBox() {
|
|||
// } catch {}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="morse-history">
|
||||
<div id="morseHistory-textbox">{text}</div>
|
||||
<button onClick={clearHistory}>Clear History</button>
|
||||
</>
|
||||
<button id="clear-history" onClick={clearHistory}>Clear History</button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
@ -50,7 +50,8 @@ export default (function PlayMorseInput() {
|
|||
<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-volume-up-fill" onClick={handlePlay}></i>
|
||||
<input type="text" id='morseInput' value={inputValue} onChange={handleChange} placeholder="Type here." maxLength="25"/> <i className="ri-play-fill" onClick={handlePlay}></i>
|
||||
<i class="ri-stop-fill" onClick={() => playMorseWord('')}></i>
|
||||
</div>
|
||||
<div id="morseTranslation">
|
||||
<span id="morseTrans">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default (function SidebarLeft() {
|
|||
} else if (e.target.id === 'nav-legend') {
|
||||
setSidebarContent('nav-legend')
|
||||
} else {
|
||||
setSidebarContent('nav-options')
|
||||
setSidebarContent('nav-play')
|
||||
}
|
||||
let navItems = document.querySelector(".navbar").childNodes
|
||||
|
||||
|
|
@ -35,6 +35,9 @@ export default (function SidebarLeft() {
|
|||
<div className="sidebar" id="left">
|
||||
<div id="sidebar-container">
|
||||
<div className="navbar">
|
||||
<div id="nav-play" className="nav-item" onClick={navClicked}>
|
||||
Play
|
||||
</div>
|
||||
<div id="nav-learn" className="nav-item selected" onClick={navClicked}>
|
||||
Learn
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -29,12 +29,19 @@ export default React.memo(function WordListPicker() {
|
|||
|
||||
let wordLists = ['alphabet', 'numbers', 'common100', 'test', 'short']
|
||||
let options = wordLists.map((wl, index) => (<option value={wl} key={index}>{wl.substr(0,1).toUpperCase() + wl.substr(1)}</option>))
|
||||
const metadata = {
|
||||
'alphabet': {description: 'Each letter of the alphabet', count: 26},
|
||||
'numbers': {description: '0-9', count: 10},
|
||||
'common100': {description: '100 most common words', count: 100},
|
||||
'test': {description: 'A test list', count: 5},
|
||||
'short': {description: 'A short list', count: 1}
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="challengeOptions">
|
||||
<div id="wordListPicker" className="mode-picker">
|
||||
<div id="title">
|
||||
Word List
|
||||
Word List:
|
||||
</div>
|
||||
<div id="input">
|
||||
<select id="wordlist-picker" defaultValue={wordListCategory} onChange={handleClick}>
|
||||
|
|
@ -42,9 +49,10 @@ export default React.memo(function WordListPicker() {
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="wordOrderPicker" className="mode-picker">
|
||||
<div id="title">
|
||||
Word Order
|
||||
Word Order:
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<button id="sequential" className="selected" onClick={handleClick}>
|
||||
|
|
@ -55,6 +63,23 @@ export default React.memo(function WordListPicker() {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="wordlist-description" className="mode-picker">
|
||||
<div id="title">
|
||||
Description:
|
||||
</div>
|
||||
<div id="info">
|
||||
{metadata[wordListCategory]['description']}
|
||||
</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>
|
||||
)
|
||||
})
|
||||
|
|
@ -1,22 +1,42 @@
|
|||
import React, {useState, useContext} from "react"
|
||||
import { GameClockContext } from "./gameClockContext"
|
||||
import { WordFeederContext } from "./wordFeederContext"
|
||||
// import { KeyTypeContext } from "./keyTypeContext"
|
||||
import { KeyTypeContext } from "./keyTypeContext";
|
||||
import { MorseBufferContext } from "./morseBufferContext";
|
||||
import morseCode from '../data/morse-reverse.json'
|
||||
|
||||
|
||||
const ChallengeContext = React.createContext()
|
||||
|
||||
function ChallengeContextProvider(props) {
|
||||
|
||||
console.log('ChallengeContextProvider');
|
||||
|
||||
const [challengeState, setChallengeState] = useState('ready')
|
||||
const {startGameClock, stopGameClock, setGameClockTime, intervals} = useContext(GameClockContext)
|
||||
const {resetFeeder} = useContext(WordFeederContext)
|
||||
const {word, getNextWord} = useContext(WordFeederContext)
|
||||
const {morseCharBuffer, setMorseCharBuffer} = useContext(MorseBufferContext)
|
||||
|
||||
|
||||
let morseArray = morseCharBuffer.split('_').filter(l => l !== '')
|
||||
let challengeWordClass = ''
|
||||
|
||||
let correctCharIndexes = [] // Indexes of correct letters in Challenge Word
|
||||
let incorrectMorseIndexes = [] // Indexes of incorrect morse characters in morse character buffer
|
||||
|
||||
let offset = 0
|
||||
let challengeLetters
|
||||
|
||||
|
||||
function startChallenge() {
|
||||
setGameClockTime(0)
|
||||
console.log('STARTCHALLENGE');
|
||||
|
||||
let countdown
|
||||
let count = 3
|
||||
|
||||
// Challenge countdown setup
|
||||
document.getElementById('challengeReady').classList.add('starting')
|
||||
document.getElementById('challengeReady').innerHTML = `<span id="message">Challenge starting in</span><span id="count">${count}</span>`
|
||||
// Start Challenge countdown
|
||||
countdown = setInterval(() => {
|
||||
count--
|
||||
if (count === 0) {
|
||||
|
|
@ -25,7 +45,7 @@ function ChallengeContextProvider(props) {
|
|||
clearInterval(countdown)
|
||||
setTimeout(() => {
|
||||
document.getElementById('challenge-overlay').classList.add('hide')
|
||||
startGameClock()
|
||||
// Start Challenge
|
||||
setChallengeState('started')
|
||||
}, 900);
|
||||
}
|
||||
|
|
@ -34,31 +54,92 @@ function ChallengeContextProvider(props) {
|
|||
}
|
||||
|
||||
function completeChallenge() {
|
||||
stopGameClock()
|
||||
setChallengeState('completed')
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
clearInterval(intervals[i]);
|
||||
if (challengeState !== 'completed') {
|
||||
setChallengeState('completed')
|
||||
resetFeeder()
|
||||
showOverlay()
|
||||
}
|
||||
resetFeeder()
|
||||
|
||||
const challengeOverlay = document.getElementById('challenge-overlay')
|
||||
challengeOverlay.classList.remove('fade')
|
||||
challengeOverlay.classList.remove('hide')
|
||||
}
|
||||
|
||||
function cancelChallenge() {
|
||||
stopGameClock()
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
clearInterval(intervals[i]);
|
||||
if (challengeState !== 'cancelled') {
|
||||
setChallengeState('cancelled')
|
||||
resetFeeder()
|
||||
showOverlay()
|
||||
}
|
||||
setChallengeState('ready')
|
||||
resetFeeder()
|
||||
setGameClockTime(0)
|
||||
}
|
||||
|
||||
function showOverlay() {
|
||||
const challengeOverlay = document.getElementById('challenge-overlay')
|
||||
challengeOverlay.classList.remove('fade')
|
||||
challengeOverlay.classList.remove('hide')
|
||||
}
|
||||
|
||||
|
||||
// If no more words in wordlist, feeder returns first word in an array
|
||||
if (typeof word === 'object') {
|
||||
completeChallenge()
|
||||
challengeLetters = word[0].split('')
|
||||
}
|
||||
else {
|
||||
challengeLetters = word.split('')
|
||||
}
|
||||
|
||||
// Iterate through the morse character buffer and compare with each letter of challenge word
|
||||
morseArray.forEach((item, index) => {
|
||||
if (morseCharBuffer.slice(-1) === '_') { // If end of morse character
|
||||
|
||||
let morseLetter = morseCode[morseArray[index]] || '[?]'
|
||||
let challengeLetter = challengeLetters[index-offset].toLowerCase()
|
||||
|
||||
if (morseLetter === challengeLetter) {
|
||||
correctCharIndexes.push(index-offset)
|
||||
console.log('morseCharBuffer', morseCharBuffer);
|
||||
|
||||
document.getElementById('challengeWord').childNodes[index-offset].classList.add('correct')
|
||||
// incorrectCharIndex = null
|
||||
}
|
||||
else {
|
||||
// incorrectCharIndex = index-offset
|
||||
incorrectMorseIndexes.push(index)
|
||||
if (incorrectMorseIndexes.length > 0) {
|
||||
setMorseCharBuffer(prev => {
|
||||
let newState = prev.split('_').filter(l => l !== '')
|
||||
newState.splice(incorrectMorseIndexes[0], 1)
|
||||
newState = newState.join('_') + '_'
|
||||
|
||||
return newState
|
||||
})
|
||||
incorrectMorseIndexes.splice(1,incorrectMorseIndexes.length)
|
||||
}
|
||||
offset = incorrectMorseIndexes.length
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Next word once all correct
|
||||
if (correctCharIndexes.length === challengeLetters.length) {
|
||||
challengeWordClass = 'correct'
|
||||
setTimeout(() => {
|
||||
setMorseCharBuffer('')
|
||||
morseArray = []
|
||||
incorrectMorseIndexes = []
|
||||
offset = 0
|
||||
if (document.getElementById('challengeWord') !== null) {
|
||||
document.getElementById('challengeWord').childNodes.forEach(node => {
|
||||
node.classList = "cLetter"
|
||||
})
|
||||
}
|
||||
}, 800)
|
||||
setTimeout(() => {
|
||||
if (correctCharIndexes.length > 0) {
|
||||
correctCharIndexes = []
|
||||
getNextWord()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<ChallengeContext.Provider value={{
|
||||
|
|
@ -66,7 +147,10 @@ function ChallengeContextProvider(props) {
|
|||
setChallengeState: setChallengeState,
|
||||
startChallenge: startChallenge,
|
||||
completeChallenge: completeChallenge,
|
||||
cancelChallenge: cancelChallenge
|
||||
cancelChallenge: cancelChallenge,
|
||||
challengeWordClass: challengeWordClass,
|
||||
morseArray: morseArray,
|
||||
incorrectMorseIndexes: incorrectMorseIndexes
|
||||
}}>
|
||||
{props.children}
|
||||
</ChallengeContext.Provider>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
import React, {useState} from "react"
|
||||
import React, {useState, useContext, useEffect} from "react"
|
||||
import { ChallengeContext } from "./challengeContext"
|
||||
// import { KeyTypeContext } from "./keyTypeContext"
|
||||
const GameClockContext = React.createContext()
|
||||
|
||||
function GameClockContextProvider(props) {
|
||||
|
||||
|
||||
const [gameClockTime, setGameClockTime] = useState(0)
|
||||
const [clockIsRunning, setClockIsRunning] = useState(false)
|
||||
// const [gameClockTimer, setGameClockTimer] = useState(0)
|
||||
|
||||
// let intervals = []
|
||||
const [intervals, setIntervals] = useState([])
|
||||
const {challengeState, setChallengeState} = useContext(ChallengeContext)
|
||||
|
||||
|
||||
function startGameClock() {
|
||||
console.log('before clock');
|
||||
if (!clockIsRunning) {
|
||||
console.log('after clock');
|
||||
setClockIsRunning(true)
|
||||
setIntervals(prev => [...prev, (setInterval(() => {
|
||||
if (document.getElementById('gameClock') === null) {
|
||||
|
|
@ -40,6 +41,27 @@ function GameClockContextProvider(props) {
|
|||
clearInterval(intervals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
switch (challengeState) {
|
||||
case 'ready':
|
||||
setGameClockTime(0)
|
||||
cleanup()
|
||||
break
|
||||
case 'started':
|
||||
startGameClock()
|
||||
break
|
||||
case 'completed':
|
||||
stopGameClock()
|
||||
break
|
||||
case 'cancelled':
|
||||
stopGameClock()
|
||||
setChallengeState('ready')
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
}, [challengeState])
|
||||
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import React, {useState} from "react"
|
|||
const KeyTypeContext = React.createContext()
|
||||
|
||||
function KeyTypeContextProvider(props) {
|
||||
console.log('KeyTypeContextProvider');
|
||||
|
||||
const [keyType, setKeyType] = useState('straight')
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { WordListPickerContext } from "./wordListPickerContext"
|
|||
const WordFeederContext = React.createContext()
|
||||
|
||||
function WordFeederContextProvider(props) {
|
||||
|
||||
// let wordList = ['hi', 'morse', 'code', 'hello', 'gene']
|
||||
const {wordList, wordListShuffled} = useContext(WordListPickerContext)
|
||||
|
||||
|
|
|
|||
444
src/css/App.css
444
src/css/App.css
|
|
@ -160,6 +160,10 @@ html, body {
|
|||
border-color: #508090;
|
||||
}
|
||||
|
||||
#main-content .sidebar#left #sidebar-container .navbar .nav-item#nav-play {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#main-content .sidebar#left #sidebar-container #info-icon {
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
|
|
@ -239,7 +243,7 @@ html, body {
|
|||
height: fit-content;
|
||||
padding: 2.5em;
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 0.9rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.5em;
|
||||
opacity: 100%;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
|
|
@ -481,7 +485,22 @@ i[class*="ri-"] {
|
|||
margin-bottom: 45px;
|
||||
}
|
||||
|
||||
#playMorseInput i:hover {
|
||||
#playMorseInput #input {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#playMorseInput #input i {
|
||||
font-size: 1.3em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#playMorseInput #input i:hover {
|
||||
color: goldenrod;
|
||||
}
|
||||
|
||||
|
|
@ -491,7 +510,7 @@ i[class*="ri-"] {
|
|||
border: 1px solid #ddd;
|
||||
height: 1.5rem;
|
||||
font-size: 0.9em;
|
||||
width: 70%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#playMorseInput #morseTrans {
|
||||
|
|
@ -614,6 +633,8 @@ i[class*="ri-"] {
|
|||
}
|
||||
|
||||
#morseButton {
|
||||
-ms-touch-action: manipulation;
|
||||
touch-action: manipulation;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-top: 30px;
|
||||
|
|
@ -781,18 +802,26 @@ i[class*="ri-"] {
|
|||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: 1.5rem;
|
||||
height: 250px;
|
||||
background: #fefefe;
|
||||
margin-top: 30%;
|
||||
width: 45%;
|
||||
padding: 1.7em;
|
||||
height: 40%;
|
||||
background: #eee;
|
||||
margin-top: 25%;
|
||||
border-radius: 5px;
|
||||
-webkit-box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.5);
|
||||
box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.5);
|
||||
border: 3px solid #666;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #notify-title, #challenge-overlay #challengeComplete #notify-title {
|
||||
font-size: 2.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #message, #challenge-overlay #challengeComplete #message {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #count, #challenge-overlay #challengeComplete #count {
|
||||
|
|
@ -817,13 +846,24 @@ i[class*="ri-"] {
|
|||
margin-right: 10px;
|
||||
font-size: 0.75em;
|
||||
color: #333;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady button#startChallenge, #challenge-overlay #challengeReady button#continue, #challenge-overlay #challengeComplete button#startChallenge, #challenge-overlay #challengeComplete button#continue {
|
||||
font-size: 1.2em;
|
||||
width: 100%;
|
||||
font-size: 1.7em;
|
||||
font-weight: bold;
|
||||
padding: 0.3em;
|
||||
background: #666;
|
||||
color: goldenrod;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.3rem;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady button#startChallenge:active, #challenge-overlay #challengeReady button#continue:active, #challenge-overlay #challengeComplete button#startChallenge:active, #challenge-overlay #challengeComplete button#continue:active {
|
||||
-webkit-transform: translateY(3px);
|
||||
transform: translateY(3px);
|
||||
-webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady button.selected, #challenge-overlay #challengeComplete button.selected {
|
||||
|
|
@ -832,6 +872,7 @@ i[class*="ri-"] {
|
|||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions, #challenge-overlay #challengeComplete #challengeOptions {
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
|
|
@ -842,12 +883,13 @@ i[class*="ri-"] {
|
|||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-box-align: start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker, #challenge-overlay #challengeComplete #challengeOptions .mode-picker {
|
||||
width: 90%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
|
|
@ -865,7 +907,7 @@ i[class*="ri-"] {
|
|||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#title, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#title {
|
||||
font-weight: bold;
|
||||
font-size: 1.08em;
|
||||
font-size: 1.4em;
|
||||
height: 100%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
|
|
@ -889,45 +931,68 @@ i[class*="ri-"] {
|
|||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input {
|
||||
margin-left: 10px;
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#buttons button, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#buttons button {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#info, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#info {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input input, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input input {
|
||||
width: 50px;
|
||||
-webkit-appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ddd;
|
||||
height: 1.3rem;
|
||||
font-size: 0.75em;
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input {
|
||||
margin-left: 10px;
|
||||
margin-top: 0.25em;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input select, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input select {
|
||||
height: 1.4rem;
|
||||
height: auto;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input button, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
#challenge-header {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#challenge-overlay #challengeReady #challengeOptions .mode-picker div#input button i, #challenge-overlay #challengeComplete #challengeOptions .mode-picker div#input button i {
|
||||
position: relative;
|
||||
left: -1px;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
#challenge-header #gameClock {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
#challenge-header #challengeControls button {
|
||||
border: 0px;
|
||||
border-radius: 5px;
|
||||
padding: 0.3em;
|
||||
font-size: 1.2em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
#challenge-header #challengeControls button:hover {
|
||||
color: maroon;
|
||||
}
|
||||
|
||||
#challengeWord {
|
||||
|
|
@ -1209,12 +1274,29 @@ i[class*="ri-"] {
|
|||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#morseHistory-textbox {
|
||||
#morse-history {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: end;
|
||||
-ms-flex-align: end;
|
||||
align-items: flex-end;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
#morse-history #morseHistory-textbox {
|
||||
background: #f8f8f8;
|
||||
border-radius: 5px;
|
||||
min-height: 4em;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
font-family: Courier;
|
||||
font-size: 1.5rem;
|
||||
|
|
@ -1227,7 +1309,7 @@ i[class*="ri-"] {
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#morseHistory-textbox span {
|
||||
#morse-history #morseHistory-textbox span {
|
||||
margin: 5px;
|
||||
background: #fdfdfd;
|
||||
height: 1.5rem;
|
||||
|
|
@ -1347,4 +1429,284 @@ i[class*="ri-"] {
|
|||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 415px) {
|
||||
html, body, #root, #main-interface {
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
#header {
|
||||
font-size: 2.1em;
|
||||
line-height: 1.2em;
|
||||
height: auto;
|
||||
}
|
||||
#playerAndLegend {
|
||||
padding: 0 !important;
|
||||
overflow-x: hidden;
|
||||
width: 100vw;
|
||||
}
|
||||
#playerAndLegend #legend {
|
||||
width: 100vw;
|
||||
}
|
||||
#legend {
|
||||
margin-top: 0px;
|
||||
background: #eee;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-pack: space-evenly;
|
||||
-ms-flex-pack: space-evenly;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
#legend #legend-title {
|
||||
margin-left: 0em;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
#legend #legend-items {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
height: -webkit-fit-content;
|
||||
height: -moz-fit-content;
|
||||
height: fit-content;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#legend #legend-items .item, #legend #legend-items span {
|
||||
cursor: pointer;
|
||||
}
|
||||
#legend #legend-items .item {
|
||||
font-family: "Courier", monospace;
|
||||
font-size: 0.7em;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: 20%;
|
||||
margin: 5px;
|
||||
padding: 0.3em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
-webkit-transition: all 50ms ease-in-out;
|
||||
transition: all 50ms ease-in-out;
|
||||
background: #ddd;
|
||||
border: 0px;
|
||||
background: #eee;
|
||||
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.35), 0px -1px 1px white;
|
||||
}
|
||||
#legend #legend-items .item span {
|
||||
-webkit-transition: all 50ms ease-in-out;
|
||||
transition: all 50ms ease-in-out;
|
||||
}
|
||||
#legend #legend-items .item:active {
|
||||
-webkit-transform: scale(0.95);
|
||||
transform: scale(0.95);
|
||||
border-color: rgba(112, 128, 144, 0.6);
|
||||
background: #ddd;
|
||||
}
|
||||
#legend #legend-items .item:active span:first-child {
|
||||
background: rgba(112, 128, 144, 0.6);
|
||||
}
|
||||
#legend #legend-items .item:hover {
|
||||
border-color: rgba(112, 128, 144, 0.6);
|
||||
background: #ddd;
|
||||
}
|
||||
#legend #legend-items .item:hover span:first-child {
|
||||
background: rgba(112, 128, 144, 0.6);
|
||||
}
|
||||
#legend #legend-items .item span:first-child {
|
||||
display: inline-block;
|
||||
padding: 1px;
|
||||
width: 1.5em;
|
||||
background: #d6d6d6;
|
||||
border-radius: 2px;
|
||||
font-size: 1.5em;
|
||||
-webkit-transition: all 75ms ease-in-out;
|
||||
transition: all 75ms ease-in-out;
|
||||
}
|
||||
#legend #legend-items .item span:last-child {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
display: inline-block;
|
||||
padding-left: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
#main-content {
|
||||
top: 2.5em;
|
||||
width: 100vw;
|
||||
}
|
||||
#main-content .sidebar#left {
|
||||
min-width: 100vw;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
transition: all 500ms ease-in-out;
|
||||
}
|
||||
#main-content .sidebar#left.hide {
|
||||
left: calc(-100vw + 40px);
|
||||
top: 50px;
|
||||
overflow-y: hidden;
|
||||
background: transparent;
|
||||
-webkit-box-shadow: 0px 0px 0px transparent;
|
||||
box-shadow: 0px 0px 0px transparent;
|
||||
}
|
||||
#main-content .sidebar#left.hide #sidebar-container #sidebar-content #info {
|
||||
opacity: 0%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
#main-content .sidebar#left.hide #sidebar-container #info-icon {
|
||||
background: white;
|
||||
}
|
||||
#main-content .sidebar#left.hide #sidebar-container #info-icon::after {
|
||||
content: ">";
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container {
|
||||
width: 100%;
|
||||
padding: 0em;
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container .navbar {
|
||||
width: 100%;
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container .navbar .nav-item {
|
||||
width: 25%;
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container .navbar .nav-item#nav-play {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container #info-icon {
|
||||
display: none;
|
||||
}
|
||||
#main-content .sidebar#left #sidebar-container #sidebar-content #info {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
}
|
||||
#main-content #main-interface {
|
||||
width: 100vw;
|
||||
left: 0;
|
||||
}
|
||||
#main-content #main-interface #morseBufferDisplay {
|
||||
margin-bottom: 0px;
|
||||
height: -webkit-fit-content;
|
||||
height: -moz-fit-content;
|
||||
height: fit-content;
|
||||
}
|
||||
#main-content #main-interface #morseBufferDisplay #overlay {
|
||||
-webkit-box-shadow: inset 20px 0px 20px -5px #eee;
|
||||
box-shadow: inset 20px 0px 20px -5px #eee;
|
||||
}
|
||||
#main-content #main-interface #morseBufferDisplay #alphanumeric-container {
|
||||
text-align: center;
|
||||
max-width: 75%;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-top: 0px;
|
||||
}
|
||||
#main-content #main-interface #morseBufferDisplay #alphanumeric-container #alphanumeric {
|
||||
height: 4rem;
|
||||
padding-top: 0.45rem;
|
||||
font-size: 3rem;
|
||||
margin-bottom: 0px;
|
||||
border-radius: 3px;
|
||||
float: right;
|
||||
}
|
||||
#main-content #main-interface * {
|
||||
z-index: 1000;
|
||||
}
|
||||
#main-content #main-interface.expandLeft {
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
#main-content #main-interface #morse-history {
|
||||
width: 95%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
#main-content #main-interface #morse-history #morseHistory-textbox {
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
padding: 5px;
|
||||
margin: 0px;
|
||||
min-height: 2.3em;
|
||||
}
|
||||
#main-content #main-interface #morse-history #clear-history {
|
||||
border: 0px;
|
||||
}
|
||||
#main-content #main-interface #morseButton {
|
||||
margin-top: 5px;
|
||||
}
|
||||
#main-content #main-interface #mainOptions {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
height: 10em;
|
||||
width: 100vw;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #title, #main-content #main-interface #mainOptions #options-right .mode-picker #title {
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
width: 5em;
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #title span#range, #main-content #main-interface #mainOptions #options-right .mode-picker #title span#range {
|
||||
display: none;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #buttons button, #main-content #main-interface #mainOptions #options-right .mode-picker #buttons button {
|
||||
margin: 5px;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #input, #main-content #main-interface #mainOptions #options-right .mode-picker #input {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #input input, #main-content #main-interface #mainOptions #options-right .mode-picker #input input {
|
||||
height: 1.1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #input select, #main-content #main-interface #mainOptions #options-right .mode-picker #input select {
|
||||
height: 1.4rem;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #input button, #main-content #main-interface #mainOptions #options-right .mode-picker #input button {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
border-radius: 3px;
|
||||
font-size: 1em;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker #input button i, #main-content #main-interface #mainOptions #options-right .mode-picker #input button i {
|
||||
left: -7px;
|
||||
top: -3px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
#main-content #main-interface #mainOptions #options-left .mode-picker button, #main-content #main-interface #mainOptions #options-right .mode-picker button {
|
||||
font-size: 0.8em;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
/*# sourceMappingURL=App.css.map */
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -113,12 +113,12 @@ function useMorsePlayer() {
|
|||
timeouts.push(setTimeout(() => {
|
||||
|
||||
}, delay))
|
||||
delay += ditMaxTime*3
|
||||
delay += ditMaxTime*2
|
||||
} else if (char === '/') {
|
||||
timeouts.push(setTimeout(() => {
|
||||
|
||||
}, delay))
|
||||
delay += ditMaxTime*7
|
||||
delay += ditMaxTime*6
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ html, body {
|
|||
// margin-top: 450px;
|
||||
// box-shadow: inset 0px 3px 3px rgba(0,0,0,0.3);
|
||||
|
||||
|
||||
.nav-item {
|
||||
// border: 1px solid black;
|
||||
padding: 10px;
|
||||
|
|
@ -162,6 +163,9 @@ html, body {
|
|||
&.selected {
|
||||
border-color: rgb(80, 128, 144);
|
||||
}
|
||||
&#nav-play {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +224,7 @@ html, body {
|
|||
height: fit-content;
|
||||
padding: 2.5em;
|
||||
font-family: $main-font;
|
||||
font-size: 0.9rem;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.5em;
|
||||
opacity: 100%;
|
||||
// overflow-y: scroll;
|
||||
|
|
@ -545,30 +549,44 @@ i[class*="ri-"] {
|
|||
}
|
||||
|
||||
|
||||
|
||||
#playMorseInput {
|
||||
// border: 1px solid #bbb;
|
||||
background: #ddd;
|
||||
width: 400px;
|
||||
height: 10em;
|
||||
padding: 1em;
|
||||
// border: 1px solid #bbb;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
// justify-content: center;
|
||||
margin-bottom: 45px;
|
||||
// overflow: hidden;
|
||||
|
||||
i:hover {
|
||||
color: goldenrod;
|
||||
}
|
||||
#input input {
|
||||
padding-left: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ddd;
|
||||
height: 1.5rem;
|
||||
font-size: 0.9em;
|
||||
width: 70%;
|
||||
|
||||
#input {
|
||||
// border: 1px solid red;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
|
||||
i {
|
||||
// background: blue;
|
||||
font-size: 1.3em;
|
||||
display: inline-block;
|
||||
|
||||
&:hover {
|
||||
color: goldenrod;
|
||||
}
|
||||
}
|
||||
input {
|
||||
padding-left: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ddd;
|
||||
height: 1.5rem;
|
||||
font-size: 0.9em;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
#morseTrans {
|
||||
|
|
@ -692,6 +710,9 @@ i[class*="ri-"] {
|
|||
$button-diameter: 100px;
|
||||
$button-radius: 50px;
|
||||
#morseButton {
|
||||
|
||||
touch-action: manipulation; // Disable double-tap to zoom on mobile devices
|
||||
|
||||
width: $button-diameter;
|
||||
height: $button-diameter;
|
||||
margin-top: 30px;
|
||||
|
|
@ -886,19 +907,25 @@ $button-radius: 50px;
|
|||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
|
||||
// width: 400px;
|
||||
padding: 1.5rem;
|
||||
height: 250px;
|
||||
// background: $main-bg-color-light;
|
||||
background: #fefefe;
|
||||
margin-top: 30%;
|
||||
width: 45%;
|
||||
padding: 1.7em;
|
||||
height: 40%;
|
||||
background: $main-bg-color-light;
|
||||
// background: #fefefe;
|
||||
margin-top: 25%;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 5px 15px rgba(0,0,0,0.5);
|
||||
border: 3px solid #666;
|
||||
|
||||
#message {
|
||||
font-size: 2em;
|
||||
#notify-title {
|
||||
font-size: 2.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
#message {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-size: 1.7em;
|
||||
}
|
||||
#count {
|
||||
font-size: 4.5em;
|
||||
font-weight: bold;
|
||||
|
|
@ -917,41 +944,55 @@ $button-radius: 50px;
|
|||
|
||||
font-size: 0.75em;
|
||||
color: $main-font-color-light;
|
||||
max-width: 250px;
|
||||
// max-width: 250px;
|
||||
&#startChallenge, &#continue {
|
||||
font-size: 1.2em;
|
||||
width: 100%;
|
||||
font-size: 1.7em;
|
||||
font-weight: bold;
|
||||
padding: 0.3em;
|
||||
background: #666;
|
||||
color: goldenrod;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.3rem;
|
||||
|
||||
// &:hover {
|
||||
// text-shadow: 0px 0px 7px rgba(255,255,255,0.3);
|
||||
// }
|
||||
&:active {
|
||||
transform: translateY(3px);
|
||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
&.selected {
|
||||
box-shadow: $main-box-shadow-light-selected;
|
||||
}
|
||||
}
|
||||
#challengeOptions {
|
||||
// border: 1px solid blue;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
// border: 1px solid blue;
|
||||
align-items: center;
|
||||
|
||||
.mode-picker {
|
||||
// border: 1px solid green;
|
||||
// width: 300px;
|
||||
width: 90%;
|
||||
display: flex;
|
||||
// align-self: flex-start;s
|
||||
align-content: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
|
||||
div {
|
||||
padding: 5px;
|
||||
height: 2.4em;
|
||||
}
|
||||
|
||||
div#title {
|
||||
font-weight: bold;
|
||||
font-size: 1.08em;
|
||||
// border: 1px solid red;
|
||||
font-weight: bold;
|
||||
font-size: 1.4em;
|
||||
height: 100%;
|
||||
// width: 40%;
|
||||
display: flex;
|
||||
padding-left: 0px;
|
||||
justify-content: flex-start;
|
||||
|
|
@ -962,36 +1003,61 @@ $button-radius: 50px;
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
button {
|
||||
font-size: 1rem;
|
||||
// &:hover {
|
||||
// color: goldenrod;
|
||||
// }
|
||||
// &:active {
|
||||
// box-shadow: $main-box-shadow-light-selected;
|
||||
// }
|
||||
}
|
||||
}
|
||||
div#info {
|
||||
// border: 1px solid black;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
height: 100%;
|
||||
}
|
||||
div#input {
|
||||
margin-left: 10px;
|
||||
margin-top: 0.25em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
input {
|
||||
width: 50px;
|
||||
appearance: textfield;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ddd;
|
||||
height: 1.3rem;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
justify-content: center;
|
||||
|
||||
select {
|
||||
height: 1.4rem;
|
||||
}
|
||||
button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
// line-height: 10px;
|
||||
i {
|
||||
position: relative;
|
||||
left: -1px;
|
||||
// top: -2px;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
height: auto;
|
||||
// padding: 5px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
// input {
|
||||
// width: 50px;
|
||||
// appearance: textfield;
|
||||
// text-align: center;
|
||||
// border-radius: 3px;
|
||||
// border: 1px solid #ddd;
|
||||
// height: 1.3rem;
|
||||
// font-size: 0.75em;
|
||||
// }
|
||||
|
||||
// button {
|
||||
// width: 20px;
|
||||
// height: 20px;
|
||||
// border-radius: 3px;
|
||||
// // line-height: 10px;
|
||||
// i {
|
||||
// position: relative;
|
||||
// left: -1px;
|
||||
// // top: -2px;
|
||||
// font-size: 1.1em;
|
||||
// font-weight: bold;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -999,6 +1065,29 @@ $button-radius: 50px;
|
|||
|
||||
}
|
||||
|
||||
#challenge-header {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
#gameClock {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
#challengeControls {
|
||||
button {
|
||||
border: 0px;
|
||||
border-radius: 5px;
|
||||
padding: 0.3em;
|
||||
font-size: 1.2em;
|
||||
color: #555;
|
||||
&:hover {
|
||||
color: maroon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#challengeWord {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -1276,30 +1365,37 @@ $button-radius: 50px;
|
|||
// font-family: 'Verdana';
|
||||
// font-size: 1.5em;
|
||||
// }
|
||||
|
||||
#morseHistory-textbox {
|
||||
// border: 1px solid cyan;
|
||||
background: #f8f8f8;
|
||||
border-radius: 5px;
|
||||
min-height: 4em;
|
||||
#morse-history {
|
||||
// border: 1px solid blue;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
padding: 0.5em;
|
||||
font-family: Courier;
|
||||
font-size: 1.5rem;
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
span {
|
||||
margin: 5px;
|
||||
background: #fdfdfd;
|
||||
height: 1.5rem;
|
||||
padding: 4px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
border-radius: $main-border-radius;
|
||||
box-shadow: $main-box-shadow-dark;
|
||||
#morseHistory-textbox {
|
||||
// border: 1px solid cyan;
|
||||
background: #f8f8f8;
|
||||
border-radius: 5px;
|
||||
min-height: 4em;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
font-family: Courier;
|
||||
font-size: 1.5rem;
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
span {
|
||||
margin: 5px;
|
||||
background: #fdfdfd;
|
||||
height: 1.5rem;
|
||||
padding: 4px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
border-radius: $main-border-radius;
|
||||
box-shadow: $main-box-shadow-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1424,4 +1520,326 @@ $button-radius: 50px;
|
|||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// @media screen and (max-width: 415px) {
|
||||
@media only screen and (max-width: 415px) {
|
||||
|
||||
html, body, #root, #main-interface {
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
#header {
|
||||
font-size: 2.1em;
|
||||
line-height: 1.2em;
|
||||
height: auto;
|
||||
}
|
||||
#playerAndLegend {
|
||||
// border: 1px solid blue;
|
||||
padding: 0 !important;
|
||||
overflow-x: hidden;
|
||||
width: 100vw;
|
||||
#legend {
|
||||
// margin-left: 2em;
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
#legend {
|
||||
margin-top: 0px;
|
||||
// width: 100%;
|
||||
// border: 1px solid orange;
|
||||
|
||||
background: $main-bg-color-light;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
|
||||
#legend-title {
|
||||
// border: 1px solid purple;
|
||||
margin-left: 0em;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
#legend-items {
|
||||
// border: 1px solid blue;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
margin-bottom: 10px;
|
||||
.item, span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// &#letters .item {
|
||||
// width: 17%;
|
||||
// }
|
||||
// &#numbers .item {
|
||||
// width: 18%;
|
||||
// }
|
||||
// &#special .item {
|
||||
// width: 20%;
|
||||
// }
|
||||
|
||||
.item {
|
||||
font-family: $ditDah-font;
|
||||
font-size: 0.7em;
|
||||
// height: 2em;
|
||||
// height: 2em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// justify-content: space-between;
|
||||
width: 20%;
|
||||
|
||||
margin: 5px;
|
||||
padding: 0.3em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
transition: all 50ms ease-in-out;
|
||||
background: #ddd;
|
||||
|
||||
border: 0px;
|
||||
background: $main-bg-color-light;
|
||||
box-shadow: $main-box-shadow-light;
|
||||
span {
|
||||
transition: all 50ms ease-in-out;
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
border-color: rgba(112, 128, 144,0.6);
|
||||
background: #ddd;
|
||||
span:first-child {
|
||||
background: rgba(112, 128, 144,0.6);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
border-color: rgba(112, 128, 144,0.6);
|
||||
background: #ddd;
|
||||
span:first-child {
|
||||
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 {
|
||||
display: inline-block;
|
||||
padding: 1px;
|
||||
width: 1.5em;
|
||||
background: #d6d6d6;
|
||||
border-radius: 2px;
|
||||
font-size: 1.5em;
|
||||
|
||||
transition: all 75ms ease-in-out;
|
||||
}
|
||||
span:last-child {
|
||||
// background: #08c;
|
||||
// font-family: $ditDah-font;
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
display: inline-block;
|
||||
padding-left: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#main-content {
|
||||
top: 2.5em;
|
||||
width: 100vw;
|
||||
.sidebar#left {
|
||||
min-width: 100vw;
|
||||
// z-index: -5;
|
||||
transition: all 500ms ease-in-out;
|
||||
|
||||
&.hide {
|
||||
left: calc(-100vw + 40px);
|
||||
top: 50px;
|
||||
overflow-y: hidden;
|
||||
background: transparent;
|
||||
box-shadow: 0px 0px 0px transparent;
|
||||
|
||||
#sidebar-container {
|
||||
|
||||
#sidebar-content #info {
|
||||
opacity: 0%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
#info-icon {
|
||||
// top: calc(100vh - 7em);
|
||||
background: white;
|
||||
&::after {
|
||||
content: ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#sidebar-container {
|
||||
width: 100%;
|
||||
padding: 0em;
|
||||
|
||||
.navbar {
|
||||
width: 100%;
|
||||
// z-index: 11000;
|
||||
|
||||
.nav-item {
|
||||
width: 25%;
|
||||
// z-index: 11000;
|
||||
|
||||
&#nav-play {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
#info-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
#info {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#main-interface {
|
||||
width: 100vw;
|
||||
left: 0;
|
||||
#morseBufferDisplay {
|
||||
// background: white;
|
||||
margin-bottom: 0px;
|
||||
height: fit-content;
|
||||
#overlay {
|
||||
// background: blue;
|
||||
box-shadow: inset 20px 0px 20px -5px $main-bg-color-light;
|
||||
}
|
||||
#alphanumeric-container {
|
||||
// border: 1px solid red;
|
||||
text-align: center;
|
||||
max-width: 75%;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-top: 0px;
|
||||
|
||||
#alphanumeric {
|
||||
// border: 1px solid blue;
|
||||
|
||||
height: 4rem;
|
||||
padding-top: 0.45rem;
|
||||
font-size: 3rem;
|
||||
margin-bottom: 0px;
|
||||
border-radius: $main-border-radius;
|
||||
// box-shadow: $main-box-shadow-light;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
* {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
&.expandLeft {
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
#morse-history {
|
||||
// border: 1px solid blue;
|
||||
width: 95%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
#morseHistory-textbox {
|
||||
// border: 1px solid blue;
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
padding: 5px;
|
||||
margin: 0px;
|
||||
min-height: 2.3em;
|
||||
}
|
||||
#clear-history {
|
||||
border: 0px;
|
||||
}
|
||||
}
|
||||
#morseButton {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
||||
#mainOptions {
|
||||
// border: 1px solid red;
|
||||
flex-direction: column;
|
||||
height: 10em;
|
||||
width: 100vw;
|
||||
|
||||
#options-left, #options-right {
|
||||
|
||||
.mode-picker {
|
||||
|
||||
#title {
|
||||
// border: 1px solid red;
|
||||
justify-content: flex-end;
|
||||
width: 5em;
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
span#range {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#buttons {
|
||||
button {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
#input {
|
||||
font-size: 0.8em;
|
||||
input {
|
||||
height: 1.1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
select {
|
||||
height: 1.4rem;
|
||||
}
|
||||
button {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
border-radius: 3px;
|
||||
font-size: 1em;
|
||||
|
||||
i {
|
||||
left: -7px;
|
||||
top: -3px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
button {
|
||||
font-size: 0.8em;
|
||||
color: $main-font-color-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue