diff options
| author | Yuval Adam <_@yuv.al> | 2025-03-09 21:59:57 +0100 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-03-09 21:59:57 +0100 |
| commit | af679f88551205753885068666ff4e9cad845b8c (patch) | |
| tree | 87820740a547f7381cd14e5bc32874e330cc352d /src/components | |
| parent | 72c70fa825a63bfad125c7ae8dc4be0cc35ec85b (diff) | |
add emed start button
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/MorseGame.tsx | 171 | ||||
| -rw-r--r-- | src/components/OptionButtons.css | 33 |
2 files changed, 132 insertions, 72 deletions
diff --git a/src/components/MorseGame.tsx b/src/components/MorseGame.tsx index 0a3b902..c140e92 100644 --- a/src/components/MorseGame.tsx +++ b/src/components/MorseGame.tsx @@ -24,6 +24,7 @@ const MorseGame: React.FC<MorseGameProps> = ({ onReset, embed = false }) => { const [wpm, setWpm] = useState(20); const [showHints, setShowHints] = useState(false); const [selectedOption, setSelectedOption] = useState<string | null>(null); + const [gameStarted, setGameStarted] = useState(!embed); // Auto-start if not in embed mode const actxRef = useRef<any>(null); const optionButtonsRef = useRef<Array<HTMLButtonElement | null>>([null, null, null, null]); @@ -43,10 +44,12 @@ const MorseGame: React.FC<MorseGameProps> = ({ onReset, embed = false }) => { actxRef.current = cw.initAudioContext({ tone: 600 }); isInitializedRef.current = true; - // Start the first round after audio context is initialized - setTimeout(() => { - newRound(); - }, 100); + // Start the first round after audio context is initialized if not in embed mode or if game already started + if (gameStarted) { + setTimeout(() => { + newRound(); + }, 100); + } } catch (error) { console.error('Failed to initialize audio context:', error); } @@ -56,14 +59,17 @@ const MorseGame: React.FC<MorseGameProps> = ({ onReset, embed = false }) => { return () => { if (actxRef.current) { try { - actxRef.current.close(); + // Check if close method exists before calling it + if (typeof actxRef.current.close === 'function') { + actxRef.current.close(); + } actxRef.current = null; } catch (error) { - console.error('Error closing audio context:', error); + console.error('Error cleaning up audio context:', error); } } }; - }, []); + }, [gameStarted]); // Generate a new round const newRound = () => { @@ -222,80 +228,101 @@ const MorseGame: React.FC<MorseGameProps> = ({ onReset, embed = false }) => { } }; + // Start the game (for embed mode) + const startGame = () => { + setGameStarted(true); + setTimeout(() => { + newRound(); + }, 100); + }; + return ( <div id="gameArea" style={{ display: 'block' }}> - <div className="score-container"> - <div className="score-widget"> - <div className="score-info"> - <div className="score-label">Score:</div> - <div className="score-value"> - <span id="score">{score}</span> / <span id="total">{totalPlayed}</span> + {embed && !gameStarted ? ( + <div className="start-game-container"> + <button + className="start-game-button" + onClick={startGame} + > + Start Game + </button> + </div> + ) : ( + <> + <div className="score-container"> + <div className="score-widget"> + <div className="score-info"> + <div className="score-label">Score:</div> + <div className="score-value"> + <span id="score">{score}</span> / <span id="total">{totalPlayed}</span> + </div> + </div> + <div className="score-tracker" id="scoreTracker"></div> </div> </div> - <div className="score-tracker" id="scoreTracker"></div> - </div> - </div> - <div className="game-container"> - <div className="game-instructions"> - <p>Listen to the Morse code and select the correct character</p> - </div> + <div className="game-container"> + <div className="game-instructions"> + <p>Listen to the Morse code and select the correct character</p> + </div> - <div className="options"> - {options.map((option, index) => ( - <button - key={index} - className={`option-button ${selectedOption === option - ? option === currentChar - ? "correct" - : "incorrect" - : "" - }`} - ref={el => { - optionButtonsRef.current[index] = el; - }} - onClick={() => handleOptionClick(option, index)} - disabled={selectedOption !== null} - > - <span className="char-display">{option}</span> - {showHints && <span className="morse-hint">{getMorseCode(option)}</span>} - </button> - ))} - </div> + <div className="options"> + {options.map((option, index) => ( + <button + key={index} + className={`option-button ${selectedOption === option + ? option === currentChar + ? "correct" + : "incorrect" + : "" + }`} + ref={el => { + optionButtonsRef.current[index] = el; + }} + onClick={() => handleOptionClick(option, index)} + disabled={selectedOption !== null} + > + <span className="char-display">{option}</span> + {showHints && <span className="morse-hint">{getMorseCode(option)}</span>} + </button> + ))} + </div> - <div className="settings"> - <div className="setting-group"> - <label htmlFor="wpmSelect">Speed:</label> - <select - id="wpmSelect" - value={wpm} - onChange={(e) => setWpm(parseInt(e.target.value))} - > - <option value="10">10 WPM</option> - <option value="15">15 WPM</option> - <option value="20">20 WPM</option> - <option value="25">25 WPM</option> - <option value="30">30 WPM</option> - </select> - </div> - <div className="setting-group hint-setting"> - <input - type="checkbox" - id="hintMode" - name="hintMode" - checked={showHints} - onChange={(e) => setShowHints(e.target.checked)} - /> - <label htmlFor="hintMode">Show Hints</label> - </div> - </div> + <div className="settings"> + <div className="setting-group"> + <label htmlFor="wpmSelect">Speed:</label> + <select + id="wpmSelect" + value={wpm} + onChange={(e) => setWpm(parseInt(e.target.value))} + > + <option value="10">10 WPM</option> + <option value="15">15 WPM</option> + <option value="20">20 WPM</option> + <option value="25">25 WPM</option> + <option value="30">30 WPM</option> + </select> + </div> + <div className="setting-group hint-setting"> + <input + type="checkbox" + id="hintMode" + name="hintMode" + checked={showHints} + onChange={(e) => setShowHints(e.target.checked)} + /> + <label htmlFor="hintMode">Show Hints</label> + </div> + </div> - {!embed && ( - <div className="keyboard-tip"> - <p>Pro Tip: Use your keyboard to select options faster!</p> + {!embed && ( + <div className="keyboard-tip"> + <p>Pro Tip: Use your keyboard to select options faster!</p> + </div> + )} </div> - )} - </div> + </> + )} </div> ); }; diff --git a/src/components/OptionButtons.css b/src/components/OptionButtons.css index a513337..e01af4b 100644 --- a/src/components/OptionButtons.css +++ b/src/components/OptionButtons.css @@ -100,3 +100,36 @@ transform: rotate(360deg); } } + +/* Start game button for embed mode */ +.start-game-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 200px; + padding: 20px; +} + +.start-game-button { + background-color: #4a6fa5; + color: white; + border: none; + border-radius: 8px; + padding: 15px 30px; + font-size: 18px; + font-weight: bold; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.start-game-button:hover { + background-color: #3a5a8c; + transform: translateY(-2px); + box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); +} + +.start-game-button:active { + transform: translateY(1px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} |
