diff options
| author | Yuval Adam <_@yuv.al> | 2025-03-09 21:31:52 +0100 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-03-09 21:31:52 +0100 |
| commit | 161516ffad6999dc24db7e5ed8e1ebd815ff1ec1 (patch) | |
| tree | ac1318859f40ee8daed0c3a97a8b78100b829d9a /src/pages/chart | |
| parent | 1623358daf03c03b1142a696cd2c9b5d27129b25 (diff) | |
Add embed pages
Diffstat (limited to 'src/pages/chart')
| -rw-r--r-- | src/pages/chart/ChartEmbedPage.tsx | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/pages/chart/ChartEmbedPage.tsx b/src/pages/chart/ChartEmbedPage.tsx new file mode 100644 index 0000000..4b485b7 --- /dev/null +++ b/src/pages/chart/ChartEmbedPage.tsx @@ -0,0 +1,162 @@ +import { useEffect, useRef } from 'react'; +import cw from 'cw'; +import '../../styles.css'; + +declare global { + interface Window { + cw: any; + } +} + +const ChartEmbedPage = () => { + const actxRef = useRef<any>(null); + + // Add meta tag for WebView compatibility and set page title + useEffect(() => { + // Set viewport for better mobile display + const viewportMeta = document.createElement('meta'); + viewportMeta.name = 'viewport'; + viewportMeta.content = 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no'; + document.head.appendChild(viewportMeta); + + // Set canonical URL + const canonicalLink = document.createElement('link'); + canonicalLink.rel = 'canonical'; + canonicalLink.href = 'https://morsehero.com/charts/embed'; + document.head.appendChild(canonicalLink); + + // Set page title + document.title = 'Morse Code Chart | Embed'; + + return () => { + document.head.removeChild(viewportMeta); + document.head.removeChild(canonicalLink); + }; + }, []); + + // Initialize audio context + const initAudio = () => { + if (actxRef.current) return; // Already initialized + + try { + actxRef.current = cw.initAudioContext({ tone: 600 }); + } catch (error) { + console.error('Failed to initialize audio context:', error); + } + }; + + // 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'); + } + + cw.play(character, { + wpm: 20, + actx: actxRef.current + }); + + // Remove the 'playing' class after the audio finishes + setTimeout(() => { + if (clickedItem) { + clickedItem.classList.remove('playing'); + } + }, 2000); + } + }; + + // 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="embed-container"> + <h1 className="embed-title">Morse Code Reference</h1> + + <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"> + {[...'1234567890'].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> + ); +}; + +// 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 ChartEmbedPage; |
