diff options
| author | Yuval Adam <_@yuv.al> | 2025-03-05 09:44:03 +0100 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-03-05 09:44:03 +0100 |
| commit | d9abe6078499206ac65a2721433f502a7b2432f1 (patch) | |
| tree | 5ea48bb732da9c98929f98587f9b49a6771f8f05 | |
| parent | 45f78bd2cb9bbef15fae24d4925da095da8c1e05 (diff) | |
Use cw dependency
| -rw-r--r-- | morsehero/package-lock.json | 7 | ||||
| -rw-r--r-- | morsehero/package.json | 1 | ||||
| -rw-r--r-- | morsehero/src/pages/HomePage.tsx | 80 | ||||
| -rw-r--r-- | morsehero/src/pages/chart/ChartPage.tsx | 43 |
4 files changed, 53 insertions, 78 deletions
diff --git a/morsehero/package-lock.json b/morsehero/package-lock.json index fb0bda6..c7079ca 100644 --- a/morsehero/package-lock.json +++ b/morsehero/package-lock.json @@ -8,6 +8,7 @@ "name": "morsehero", "version": "0.0.0", "dependencies": { + "cw": "^0.3.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.2.0" @@ -1875,6 +1876,12 @@ "dev": true, "license": "MIT" }, + "node_modules/cw": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cw/-/cw-0.3.0.tgz", + "integrity": "sha512-fI5FLB6UdeG1log8Gq7IhJl7JJ0ni4OCSHymJAXRdYLprYHnRLtT9JMPtap4liRZ/fQ54a+w/uwXZS+89C6Ybg==", + "license": "ISC" + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", diff --git a/morsehero/package.json b/morsehero/package.json index 9e69011..4967122 100644 --- a/morsehero/package.json +++ b/morsehero/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "cw": "^0.3.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.2.0" diff --git a/morsehero/src/pages/HomePage.tsx b/morsehero/src/pages/HomePage.tsx index e67a9a8..7ec4e90 100644 --- a/morsehero/src/pages/HomePage.tsx +++ b/morsehero/src/pages/HomePage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef } from 'react'; import { Link } from 'react-router'; +import * as cw from 'cw'; import '../base.css'; import '../styles.css'; @@ -19,7 +20,7 @@ const HomePage = () => { const [options, setOptions] = useState<string[]>([]); const [wpm, setWpm] = useState(20); const [showHints, setShowHints] = useState(false); - + const actxRef = useRef<any>(null); const optionButtonsRef = useRef<Array<HTMLButtonElement | null>>([null, null, null, null]); @@ -29,17 +30,13 @@ const HomePage = () => { const specialChars = '.,?/='; const allChars = letters + numbers + specialChars; - // Initialize the game when started + // Initialize the game when started - this happens on user interaction (button click) const startGame = () => { try { - if (window.cw) { - actxRef.current = window.cw.initAudioContext({ tone: 600 }); - setGameStarted(true); - newRound(); - } else { - console.error('CW.js not loaded'); - alert('Failed to initialize audio. Please try again.'); - } + // Initialize audio context on user interaction + actxRef.current = cw.initAudioContext({ tone: 600 }); + setGameStarted(true); + newRound(); } catch (error) { console.error('Failed to initialize audio context:', error); alert('Failed to initialize audio. Please try again.'); @@ -58,7 +55,7 @@ const HomePage = () => { // Generate options (one correct, three random) let newOptions = [newChar]; - + // Add three random unique characters while (newOptions.length < 4) { const randomChar = allChars[Math.floor(Math.random() * allChars.length)]; @@ -66,7 +63,7 @@ const HomePage = () => { newOptions.push(randomChar); } } - + // Shuffle options newOptions = shuffleArray(newOptions); setOptions(newOptions); @@ -78,10 +75,9 @@ const HomePage = () => { // Play Morse code for a character const playMorseCode = (char: string) => { if (actxRef.current) { - window.cw.playText({ - text: char, + cw.play(char, { wpm: wpm, - audioContext: actxRef.current + actx: actxRef.current }); } }; @@ -92,7 +88,7 @@ const HomePage = () => { // Correct answer setFeedback('Correct!'); setScore(prevScore => prevScore + 1); - + // Add to score tracker const scoreTracker = document.getElementById('scoreTracker'); if (scoreTracker) { @@ -100,25 +96,25 @@ const HomePage = () => { marker.className = 'score-marker correct'; scoreTracker.appendChild(marker); } - + // Disable all buttons optionButtonsRef.current.forEach(button => { if (button) button.disabled = true; }); - + // Highlight the correct button const correctButtonIndex = options.indexOf(currentChar); if (correctButtonIndex !== -1 && optionButtonsRef.current[correctButtonIndex]) { const button = optionButtonsRef.current[correctButtonIndex]; if (button) button.classList.add('correct'); } - + // Move to next round after delay setTimeout(newRound, 1500); } else { // Incorrect answer setFeedback('Incorrect! The correct answer was ' + currentChar); - + // Add to score tracker const scoreTracker = document.getElementById('scoreTracker'); if (scoreTracker) { @@ -126,29 +122,29 @@ const HomePage = () => { marker.className = 'score-marker incorrect'; scoreTracker.appendChild(marker); } - + // Disable all buttons optionButtonsRef.current.forEach(button => { if (button) button.disabled = true; }); - + // Highlight the incorrect button and show the correct one const selectedButtonIndex = options.indexOf(selectedChar); if (selectedButtonIndex !== -1 && optionButtonsRef.current[selectedButtonIndex]) { const button = optionButtonsRef.current[selectedButtonIndex]; if (button) button.classList.add('incorrect'); } - + const correctButtonIndex = options.indexOf(currentChar); if (correctButtonIndex !== -1 && optionButtonsRef.current[correctButtonIndex]) { const button = optionButtonsRef.current[correctButtonIndex]; if (button) button.classList.add('correct'); } - + // Move to next round after delay setTimeout(newRound, 2000); } - + setTotalPlayed(prevTotal => prevTotal + 1); }; @@ -156,9 +152,9 @@ const HomePage = () => { useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (!gameStarted) return; - + const key = event.key.toUpperCase(); - + // Find if any button has this character const index = options.findIndex(option => option === key); if (index !== -1) { @@ -172,25 +168,13 @@ const HomePage = () => { } } }; - + document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [gameStarted, options]); - // Load CW.js script - useEffect(() => { - const script = document.createElement('script'); - script.src = 'https://cdn.jsdelivr.net/npm/cw@latest/dist/cw.min.js'; - script.async = true; - document.body.appendChild(script); - - return () => { - document.body.removeChild(script); - }; - }, []); - // Utility function to shuffle an array const shuffleArray = (array: string[]) => { const newArray = [...array]; @@ -203,7 +187,7 @@ const HomePage = () => { // Get Morse code representation for a character const getMorseCode = (char: string) => { - const morseMap: {[key: string]: string} = { + const morseMap: { [key: string]: string } = { 'A': '·−', 'B': '−···', 'C': '−·−·', 'D': '−··', 'E': '·', 'F': '··−·', 'G': '−−·', 'H': '····', 'I': '··', 'J': '·−−−', 'K': '−·−', 'L': '·−··', 'M': '−−', 'N': '−·', 'O': '−−−', @@ -213,7 +197,7 @@ const HomePage = () => { '4': '····−', '5': '·····', '6': '−····', '7': '−−···', '8': '−−−··', '9': '−−−−·', '.': '·−·−·−', ',': '−−··−−', '?': '··−−··', '/': '−··−·', '=': '−···−' }; - + return morseMap[char] || ''; }; @@ -246,9 +230,9 @@ const HomePage = () => { <div className="game-container"> <div className="options"> {options.map((option, index) => ( - <button + <button key={index} - className="option-button" + className="option-button" ref={el => { optionButtonsRef.current[index] = el; }} @@ -265,7 +249,7 @@ const HomePage = () => { <div className="settings"> <label htmlFor="wpmSelect">Speed:</label> - <select + <select id="wpmSelect" value={wpm} onChange={(e) => setWpm(parseInt(e.target.value))} @@ -277,9 +261,9 @@ const HomePage = () => { <option value="30">30 WPM</option> </select> <div className="hint-setting"> - <input - type="checkbox" - id="hintMode" + <input + type="checkbox" + id="hintMode" name="hintMode" checked={showHints} onChange={(e) => setShowHints(e.target.checked)} diff --git a/morsehero/src/pages/chart/ChartPage.tsx b/morsehero/src/pages/chart/ChartPage.tsx index 9f2b56d..88c1ec2 100644 --- a/morsehero/src/pages/chart/ChartPage.tsx +++ b/morsehero/src/pages/chart/ChartPage.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef } from 'react'; import { Link } from 'react-router'; +import * as cw from 'cw'; import '../../base.css'; import './styles.css'; @@ -14,12 +15,10 @@ const ChartPage = () => { // Initialize audio context const initAudio = () => { + if (actxRef.current) return; // Already initialized + try { - if (window.cw) { - actxRef.current = window.cw.initAudioContext({ tone: 600 }); - } else { - console.error('CW.js not loaded'); - } + actxRef.current = cw.initAudioContext({ tone: 600 }); } catch (error) { console.error('Failed to initialize audio context:', error); } @@ -27,28 +26,28 @@ const ChartPage = () => { // Play Morse code for a character const playCharacter = (character: string) => { + // Initialize audio on first user interaction if (!actxRef.current) { initAudio(); } - + if (actxRef.current) { // Remove 'playing' class from all items document.querySelectorAll('.morse-item').forEach(item => { item.classList.remove('playing'); }); - + // Add 'playing' class to the clicked item const clickedItem = document.querySelector(`.morse-item[data-char="${character}"]`); if (clickedItem) { clickedItem.classList.add('playing'); } - - window.cw.playText({ - text: character, + + cw.play(character, { wpm: 20, - audioContext: actxRef.current + actx: actxRef.current }); - + // Remove the 'playing' class after the audio finishes setTimeout(() => { if (clickedItem) { @@ -58,22 +57,6 @@ const ChartPage = () => { } }; - // Load CW.js script - useEffect(() => { - const script = document.createElement('script'); - script.src = 'https://cwjs.mastercw.com/cw.min.js'; - script.async = true; - document.body.appendChild(script); - - script.onload = () => { - initAudio(); - }; - - return () => { - document.body.removeChild(script); - }; - }, []); - // Add click event listeners to all morse items useEffect(() => { const handleMorseItemClick = (e: Event) => { @@ -178,7 +161,7 @@ const ChartPage = () => { // Helper function to get morse code representation const getMorseCode = (char: string) => { - const morseMap: {[key: string]: string} = { + const morseMap: { [key: string]: string } = { 'A': '·−', 'B': '−···', 'C': '−·−·', 'D': '−··', 'E': '·', 'F': '··−·', 'G': '−−·', 'H': '····', 'I': '··', 'J': '·−−−', 'K': '−·−', 'L': '·−··', 'M': '−−', 'N': '−·', 'O': '−−−', @@ -188,7 +171,7 @@ const getMorseCode = (char: string) => { '4': '····−', '5': '·····', '6': '−····', '7': '−−···', '8': '−−−··', '9': '−−−−·', '.': '·−·−·−', ',': '−−··−−', '?': '··−−··', '/': '−··−·', '=': '−···−' }; - + return morseMap[char] || ''; }; |
