diff options
Diffstat (limited to 'morsehero/src/pages/chart/ChartPage.tsx')
| -rw-r--r-- | morsehero/src/pages/chart/ChartPage.tsx | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/morsehero/src/pages/chart/ChartPage.tsx b/morsehero/src/pages/chart/ChartPage.tsx new file mode 100644 index 0000000..9f2b56d --- /dev/null +++ b/morsehero/src/pages/chart/ChartPage.tsx @@ -0,0 +1,195 @@ +import { useEffect, useRef } from 'react'; +import { Link } from 'react-router'; +import '../../base.css'; +import './styles.css'; + +declare global { + interface Window { + cw: any; + } +} + +const ChartPage = () => { + const actxRef = useRef<any>(null); + + // Initialize audio context + const initAudio = () => { + try { + if (window.cw) { + actxRef.current = window.cw.initAudioContext({ tone: 600 }); + } else { + console.error('CW.js not loaded'); + } + } catch (error) { + console.error('Failed to initialize audio context:', error); + } + }; + + // Play Morse code for a character + const playCharacter = (character: string) => { + 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, + wpm: 20, + audioContext: actxRef.current + }); + + // Remove the 'playing' class after the audio finishes + setTimeout(() => { + if (clickedItem) { + clickedItem.classList.remove('playing'); + } + }, 2000); + } + }; + + // 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) => { + const target = e.currentTarget as HTMLElement; + const character = target.getAttribute('data-char'); + if (character) { + playCharacter(character); + } + }; + + const morseItems = document.querySelectorAll('.morse-item'); + morseItems.forEach(item => { + item.addEventListener('click', handleMorseItemClick); + }); + + return () => { + morseItems.forEach(item => { + item.removeEventListener('click', handleMorseItemClick); + }); + }; + }, []); + + return ( + <div className="container"> + <h1><Link to="/" className="title-link">Morse Hero</Link></h1> + <h2>Morse Code Chart</h2> + + <div className="chart-section"> + <h2>Letters</h2> + <div className="morse-grid"> + {[...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'].map(char => ( + <div key={char} className="morse-item" data-char={char}> + <div className="character">{char}</div> + <div className="morse">{getMorseCode(char)}</div> + </div> + ))} + </div> + </div> + + <div className="chart-section"> + <h2>Numbers</h2> + <div className="morse-grid"> + {[...'0123456789'].map(char => ( + <div key={char} className="morse-item" data-char={char}> + <div className="character">{char}</div> + <div className="morse">{getMorseCode(char)}</div> + </div> + ))} + </div> + </div> + + <div className="chart-section"> + <h2>Special Characters</h2> + <div className="morse-grid"> + {[...'.=,?/'].map(char => ( + <div key={char} className="morse-item" data-char={char}> + <div className="character">{char}</div> + <div className="morse">{getMorseCode(char)}</div> + </div> + ))} + </div> + </div> + + <div className="chart-section"> + <h2>Prosigns</h2> + <div className="morse-grid"> + <div className="morse-item"> + <div className="character">AR</div> + <div className="morse">·−·−·</div> + <div className="description">End of message</div> + </div> + <div className="morse-item"> + <div className="character">SK</div> + <div className="morse">···−·−</div> + <div className="description">End of contact</div> + </div> + <div className="morse-item"> + <div className="character">BT</div> + <div className="morse">−···−</div> + <div className="description">Break</div> + </div> + <div className="morse-item"> + <div className="character">KN</div> + <div className="morse">−·−−·</div> + <div className="description">Go only</div> + </div> + </div> + </div> + + <div className="back-link"> + <Link to="/">Back to Morse Hero</Link> + </div> + + <footer className="footer"> + <p>Click on any character to hear its Morse code sound.</p> + <p>Created with <a href="https://www.mastercw.com/cw.js/">CW.js</a>. For a complete and professional + Morse Code training solution visit <a href="https://www.mastercw.com">Master CW</a>.</p> + </footer> + </div> + ); +}; + +// Helper function to get morse code representation +const getMorseCode = (char: string) => { + const morseMap: {[key: string]: string} = { + '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': '−−··', '0': '−−−−−', '1': '·−−−−', '2': '··−−−', '3': '···−−', + '4': '····−', '5': '·····', '6': '−····', '7': '−−···', '8': '−−−··', + '9': '−−−−·', '.': '·−·−·−', ',': '−−··−−', '?': '··−−··', '/': '−··−·', '=': '−···−' + }; + + return morseMap[char] || ''; +}; + +export default ChartPage; |
