From 5bf781f3ac381744fbec035f938d69a201f75fa4 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 5 Mar 2025 12:21:25 +0100 Subject: Replace all impl with vite --- src/pages/chart/ChartPage.tsx | 178 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/pages/chart/ChartPage.tsx (limited to 'src/pages/chart/ChartPage.tsx') diff --git a/src/pages/chart/ChartPage.tsx b/src/pages/chart/ChartPage.tsx new file mode 100644 index 0000000..88c1ec2 --- /dev/null +++ b/src/pages/chart/ChartPage.tsx @@ -0,0 +1,178 @@ +import { useEffect, useRef } from 'react'; +import { Link } from 'react-router'; +import * as cw from 'cw'; +import '../../base.css'; +import './styles.css'; + +declare global { + interface Window { + cw: any; + } +} + +const ChartPage = () => { + const actxRef = useRef(null); + + // 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 ( +
+

Morse Hero

+

Morse Code Chart

+ +
+

Letters

+
+ {[...'ABCDEFGHIJKLMNOPQRSTUVWXYZ'].map(char => ( +
+
{char}
+
{getMorseCode(char)}
+
+ ))} +
+
+ +
+

Numbers

+
+ {[...'0123456789'].map(char => ( +
+
{char}
+
{getMorseCode(char)}
+
+ ))} +
+
+ +
+

Special Characters

+
+ {[...'.=,?/'].map(char => ( +
+
{char}
+
{getMorseCode(char)}
+
+ ))} +
+
+ +
+

Prosigns

+
+
+
AR
+
·−·−·
+
End of message
+
+
+
SK
+
···−·−
+
End of contact
+
+
+
BT
+
−···−
+
Break
+
+
+
KN
+
−·−−·
+
Go only
+
+
+
+ +
+ Back to Morse Hero +
+ + +
+ ); +}; + +// 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; -- cgit v1.3.1