From 9ed3ee790ef84b4dc3e0bb115ac91ae91aaa81d7 Mon Sep 17 00:00:00 2001 From: zyqunix Date: Sat, 5 Apr 2025 19:49:49 +0200 Subject: [PATCH] morse code and ip lookup --- global.css | 15 +++-- ip/index.html | 21 +++++++ ip/index.js | 48 +++++++++++++++ ip/style.css | 104 +++++++++++++++++++++++++++++++ morse/index.html | 25 ++++++++ morse/index.js | 146 ++++++++++++++++++++++++++++++++++++++++++++ morse/style.css | 33 ++++++++++ portfolio/style.css | 1 - 8 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 ip/index.html create mode 100644 ip/index.js create mode 100644 ip/style.css create mode 100644 morse/index.html create mode 100644 morse/index.js create mode 100644 morse/style.css diff --git a/global.css b/global.css index 29c5c72..6319bc1 100644 --- a/global.css +++ b/global.css @@ -37,7 +37,14 @@ a:hover, svg:hover { color: #c099ff; } -::selection { - background-color: #c099ff; - color: #2a2a2a; -} \ No newline at end of file +.card { + background-color: #252525; + padding: 20px; + border-radius: 10px; + width: 600px !important; + text-align: center; +} + +.shadow { + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); +} diff --git a/ip/index.html b/ip/index.html new file mode 100644 index 0000000..44803c0 --- /dev/null +++ b/ip/index.html @@ -0,0 +1,21 @@ + + + + IP Lookup + + + + + + +

IP Lookup

+
+ + +
Your IP: 69.420.69.69
+
+
+ + + + diff --git a/ip/index.js b/ip/index.js new file mode 100644 index 0000000..470023d --- /dev/null +++ b/ip/index.js @@ -0,0 +1,48 @@ +const lookupElem = document.getElementById('lookupElem'); +const yourIp = document.getElementById('your-ip'); + +function getFlagEmoji(countryCode) { + return countryCode + .toUpperCase() + .replace(/./g, char => String.fromCodePoint(127397 + char.charCodeAt())); +} + +function fetchIp() { + const ip = document.getElementById("ipInput").value; + fetch(`https://ipapi.co/${ip}/json/`) + .then(response => response.json()) + .then(data => { + const flag = getFlagEmoji(data.country_code || ''); + const table = ` + + + + + + + + + +
IP${data.ip}
City${data.city}
Postal Code${data.postal}
Region${data.region}
Country${flag} ${data.country_name} (${data.country_code})
Timezone${data.timezone}
Organization${data.org}
Coordinates${data.latitude}, ${data.longitude}
+ `; + document.getElementById("output").innerHTML = table; + }) + .catch(err => { + document.getElementById("output").textContent = "Error: " + err; + }); +} + +function getYour() { + fetch(`https://ipapi.co/json/?ip=ipv4`) + .then(response => response.json()) + .then(data => { + yourIp.innerHTML = data.ip; + }) + .catch(err => { + yourIp.textContent = "Error: " + err; + }); +} + +window.addEventListener('load', getYour); + +lookupElem.addEventListener('click', fetchIp); diff --git a/ip/style.css b/ip/style.css new file mode 100644 index 0000000..70199f6 --- /dev/null +++ b/ip/style.css @@ -0,0 +1,104 @@ +@import url(/global.css); + +h1 { + font-size: 2rem; + margin-bottom: 30px; +} + +input[type="text"] { + background: #1e1e1e; + border: 1px solid #444; + color: #f0f0f0; + padding: 12px 15px; + border-radius: 8px; + font-size: 1rem; + width: 70%; + margin-right: 10px; + transition: border-color 0.2s; + outline: none; + z-index: 2; +} + +button { + background: #c099ff; + color: #1e1e1e; + border: none; + padding: 12px 20px; + font-size: 1rem; + border-radius: 8px; + cursor: pointer; + transition: background 0.2s; + z-index: 2; +} + +button:hover { + background: #a875ff; +} + +#output { + margin-top: 25px; + border-radius: 10px; + width: 100%; + max-width: 640px; +} + +table { + border-collapse: collapse; + width: 100%; + border-radius: 12px; + overflow: hidden; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +th, td { + padding: 10px 14px; + border: 2px solid #2a2a2a; + background-color: #1f1f1f; +} + +th:hover, +td:hover { + background-color: #232323; +} + +th { + text-align: left; +} + +.your { + margin-top: 15px; +} + +#your-ip:not(:hover) { + filter: blur(10px); +} + +.tooltip { + display: flex; + justify-content: center; + position: relative; +} + +.tooltip::after { + content: attr(data-tooltip); + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: 125%; + background-color: #2a2a2a; + border: 2px solid rgba(150, 150, 150, 0.1); + color: #fff; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s, visibility 0.3s; + cursor: default; +} + +.tooltip:hover::after { + opacity: 1; + visibility: visible; +} diff --git a/morse/index.html b/morse/index.html new file mode 100644 index 0000000..6c7ed6d --- /dev/null +++ b/morse/index.html @@ -0,0 +1,25 @@ + + + + + + Morse Translator + + + + +
+

Morse Translator

+ + + + + + + + +
+ + + + diff --git a/morse/index.js b/morse/index.js new file mode 100644 index 0000000..ff6cc2d --- /dev/null +++ b/morse/index.js @@ -0,0 +1,146 @@ +const morseElem = document.getElementById('translate-to-morse'); +const textElem = document.getElementById('translate-to-text'); +const soundElem = document.getElementById('play-sound'); +const exportElem = document.getElementById('export'); + +const morseCode = { + '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': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----', ' ': '/' +}; + +const morseToText = Object.fromEntries(Object.entries(morseCode).map(([key, value]) => [value, key])); + +function translateToMorse() { + const text = document.getElementById('textInput').value.toUpperCase(); + const morse = text.split('').map(char => morseCode[char] || '').join(' '); + document.getElementById('morseOutput').value = morse; +} + +function translateToText() { + const morse = document.getElementById('morseOutput').value.trim(); + const text = morse.split(' ').map(code => morseToText[code] || '').join(''); + document.getElementById('textInput').value = text; +} + +function playMorseSound() { + const morse = document.getElementById('morseOutput').value.trim(); + let audioContext = new (window.AudioContext || window.webkitAudioContext)(); + let dotDuration = 200; + let dashDuration = dotDuration * 3; + let gapDuration = dotDuration; + + function playTone(freq, duration, volume) { + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(freq, audioContext.currentTime); + gainNode.gain.setValueAtTime(volume, audioContext.currentTime); + oscillator.start(); + oscillator.stop(audioContext.currentTime + duration / 1000); + } + + let position = 0; + function playMorseCode() { + if (position < morse.length) { + const symbol = morse[position]; + + if (symbol === '.') { + playTone(1000, dotDuration, 0.1); + position++; + setTimeout(playMorseCode, dotDuration + gapDuration); + } else if (symbol === '-') { + playTone(1000, dashDuration, 0.1); + position++; + setTimeout(playMorseCode, dashDuration + gapDuration); + } else if (symbol === ' ') { + position++; + setTimeout(playMorseCode, gapDuration); + } + } + } + + playMorseCode(); +} + +function exportSound() { + const morse = document.getElementById('morseOutput').value.trim(); + let dotDuration = 200; + let dashDuration = dotDuration * 3; + let gapDuration = dotDuration; + + let sampleRate = 44100; + let samples = []; + + function addSilence(duration) { + let count = (sampleRate * duration) / 1000; + for (let i = 0; i < count; i++) { + samples.push(0); + } + } + + function addTone(freq, duration) { + let count = (sampleRate * duration) / 1000; + for (let i = 0; i < count; i++) { + let t = i / sampleRate; + samples.push(Math.sin(2 * Math.PI * freq * t)); + } + } + + for (let symbol of morse) { + if (symbol === '.') { + addTone(1000, dotDuration); + addSilence(gapDuration); + } else if (symbol === '-') { + addTone(1000, dashDuration); + addSilence(gapDuration); + } else if (symbol === ' ') { + addSilence(gapDuration); + } + } + + const buffer = new ArrayBuffer(44 + samples.length * 2); + const view = new DataView(buffer); + + function writeString(offset, string) { + for (let i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } + } + + // i have no idea what this shit is or how it works, but it does :rofl: + writeString(0, 'RIFF'); + view.setUint32(4, 36 + samples.length * 2, true); + writeString(8, 'WAVE'); + writeString(12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, 1, true); + view.setUint16(22, 1, true); + view.setUint32(24, sampleRate, true); + view.setUint32(28, sampleRate * 2, true); + view.setUint16(32, 2, true); + view.setUint16(34, 16, true); + writeString(36, 'data'); + view.setUint32(40, samples.length * 2, true); + + for (let i = 0; i < samples.length; i++) { + let s = Math.max(-1, Math.min(1, samples[i])); + view.setInt16(44 + i * 2, s * 32767, true); + } + + const blob = new Blob([view], { type: 'audio/wav' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'morse-code.wav'; + a.click(); +} + + +morseElem.addEventListener('click', translateToMorse); + +textElem.addEventListener('click', translateToText); + +soundElem.addEventListener('click', playMorseSound); + +exportElem.addEventListener('click', exportSound); diff --git a/morse/style.css b/morse/style.css new file mode 100644 index 0000000..479d68d --- /dev/null +++ b/morse/style.css @@ -0,0 +1,33 @@ +@import url(/global.css); + +.container { + text-align: center; + padding: 20px; + border-radius: 20px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.7); +} + +textarea, input, button { + width: 70%; + margin-top: 10px; + padding: 10px; + border-radius: 10px; + border: none; + background-color: #333; + color: #f0f0f0; +} + +textarea { + resize: none; + margin-right: 10px; +} + +button { + cursor: pointer; + background-color: #444; +} + +button:hover { + background-color: #555; +} + diff --git a/portfolio/style.css b/portfolio/style.css index 428fe5d..065b6fe 100644 --- a/portfolio/style.css +++ b/portfolio/style.css @@ -184,7 +184,6 @@ div[class="name-percent-container"] > img.image { } .tooltip { - cursor: help; display: flex; justify-content: center; position: relative;